PageSourceSearch

https://socket.io/assets/js/fd015418.53f06705.js

js socket.io collected 2026-09-24 07:26:02 UTC 18,417 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunksample_website=self.webpackChunksample_website||[]).push([[5792],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var d=a.createContext({}),s=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(d.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,d=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=s(n),k=o,u=m["".concat(d,".").concat(k)]||m[k]||c[k]||r;return n?a.createElement(u,l(l({ref:t},p),{},{components:n})):a.createElement(u,l({ref:t},p))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=k;var i={};for(var d in t)hasOwnProperty.call(t,d)&&(i[d]=t[d]);i.originalType=e,i[m]="string"==typeof e?e:o,l[1]=i;for(var s=2;s<r;s++)l[s]=n[s];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}k.displayName="MDXCreateElement"},3813:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>d,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>m});var a=n(3117),o=(n(7294),n(3905)),r=n(941),l=n(4996);const i={title:"MongoDB adapter",sidebar_position:4,slug:"/mongo-adapter/"},d=void 0,s={unversionedId:"categories/Adapters/adapter-mongo",id:"categories/Adapters/adapter-mongo",title:"MongoDB adapter",description:"How it works",source:"@site/docs/categories/05-Adapters/adapter-mongo.md",sourceDirName:"categories/05-Adapters",slug:"/mongo-adapter/",permalink:"/docs/v4/mongo-adapter/",draft:!1,editUrl:"https://github.com/socketio/socket.io-website/edit/main/docs/categories/05-Adapters/adapter-mongo.md",tags:[],version:"current",lastUpdatedAt:1784117104,formattedLastUpdatedAt:"Jul 15, 2026",sidebarPosition:4,frontMatter:{title:"MongoDB adapter",sidebar_position:4,slug:"/mongo-adapter/"},sidebar:"sidebar",previous:{title:"Redis Streams adapter",permalink:"/docs/v4/redis-streams-adapter/"},next:{title:"Postgres adapter",permalink:"/docs/v4/postgres-adapter/"}},p={},m=[{value:"How it works",id:"how-it-works",level:2},{value:"Supported features",id:"supported-features",level:2},{value:"Installation",id:"installation",level:2},{value:"Usage",id:"usage",level:2},{value:"Usage with a capped collection",id:"usage-with-a-capped-collection",level:3},{value:"Usage with a TTL index",id:"usage-with-a-ttl-index",level:3},{value:"Options",id:"options",level:2},{value:"Common questions",id:"common-questions",level:2},{value:"Do I still need to enable sticky sessions when using the MongoDB adapter?",id:"do-i-still-need-to-enable-sticky-sessions-when-using-the-mongodb-adapter",level:3},{value:"What happens when the MongoDB cluster is down?",id:"what-happens-when-the-mongodb-cluster-is-down",level:3},{value:"Latest releases",id:"latest-releases",level:2},{value:"Emitter",id:"emitter",level:2},{value:"Installation",id:"installation-1",level:3},{value:"Usage",id:"usage-1",level:3}],c={toc:m},k="wrapper";
1function u(e){let{components:t,...n}=e;return(0,o.kt)(k,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"how-it-works"},"How it works"),(0,o.kt)("p",null,"The MongoDB adapter relies on MongoDB's ",(0,o.kt)("a",{parentName:"p",href:"https://docs.mongodb.com/manual/changeStreams/"},"Change Streams")," (and thus requires a replica set or a sharded cluster)."),(0,o.kt)("p",null,"Every packet that is sent to multiple clients (e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},'io.to("room1").emit()')," or ",(0,o.kt)("inlineCode",{parentName:"p"},"socket.broadcast.emit()"),") is:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"sent to all matching clients connected to the current server"),(0,o.kt)("li",{parentName:"ul"},"inserted in a MongoDB capped collection, and received by the other Socket.IO servers of the cluster")),(0,o.kt)(r.Z,{alt:"Diagram of how the MongoDB adapter works",sources:{light:(0,l.Z)("/images/mongo-adapter.png"),dark:(0,l.Z)("/images/mongo-adapter-dark.png")},mdxType:"ThemedImage"}),(0,o.kt)("p",null,"The source code of this adapter can be found ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/socketio/socket.io-mongo-adapter"},"here"),"."),(0,o.kt)("h2",{id:"supported-features"},"Supported features"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Feature"),(0,o.kt)("th",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"th"},"socket.io")," version"),(0,o.kt)("th",{parentName:"tr",align:null},"Support"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Socket management"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"4.0.0")),(0,o.kt)("td",{parentName:"tr",align:null},"\u2705 YES (since version ",(0,o.kt)("inlineCode",{parentName:"td"},"0.1.0"),")")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Inter-server communication"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"4.1.0")),(0,o.kt)("td",{parentName:"tr",align:null},"\u2705 YES (since version ",(0,o.kt)("inlineCode",{parentName:"td"},"0.1.0"),")")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Broadcast with acknowledgements"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/docs/v4/changelog/4.5.0"},(0,o.kt)("inlineCode",{parentName:"a"},"4.5.0"))),(0,o.kt)("td",{parentName:"tr",align:null},"\u2705 YES (since version ",(0,o.kt)("inlineCode",{parentName:"td"},"0.2.0"),")")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Connection state recovery"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/docs/v4/changelog/4.6.0"},(0,o.kt)("inlineCode",{parentName:"a"},"4.6.0"))),(0,o.kt)("td",{parentName:"tr",align:null},"\u2705 YES (since version ",(0,o.kt)("inlineCode",{parentName:"td"},"0.3.0"),")")))),(0,o.kt)("h2",{id:"installation"},"Installation"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm install @socket.io/mongo-adapter mongodb\n")),(0,o.kt)("p",null,"For TypeScript users, you might also need ",(0,o.kt)("inlineCode",{parentName:"p"},"@types/mongodb"),"."),(0,o.kt)("h2",{id:"usage"},"Usage"),(0,o.kt)("p",null,"Broadcasting packets within a Socket.IO cluster is achieved by creating MongoDB documents and using a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.mongodb.com/manual/changeStreams/"},"change stream")," on each Socket.IO server."),(0,o.kt)("p",null,"There are two ways to clean up the documents in MongoDB:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"a ",(0,o.kt)("a",{parentName:"li",href:"https://www.mongodb.com/docs/manual/core/capped-collections/"},"capped collection")),(0,o.kt)("li",{parentName:"ul"},"a ",(0,o.kt)("a",{parentName:"li",href:"https://www.mongodb.com/docs/manual/core/index-ttl/"},"TTL index"))),(0,o.kt)("h3",{id:"usage-with-a-capped-collection"},"Usage with a capped collection"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'import { Server } from "socket.io";\nimport { createAdapter } from "@socket.io/mongo-adapter";\nimport { MongoClient } from "mongodb";\n\nconst DB = "mydb";
1\nconst COLLECTION = "socket.io-adapter-events";\n\nconst io = new Server();\n\nconst mongoClient = new MongoClient("mongodb://localhost:27017/?replicaSet=rs0");\n\nawait mongoClient.connect();\n\ntry {\n  await mongoClient.db(DB).createCollection(COLLECTION, {\n    capped: true,\n    size: 1e6\n  });\n} catch (e) {\n  // collection already exists\n}\nconst mongoCollection = mongoClient.db(DB).collection(COLLECTION);\n\nio.adapter(createAdapter(mongoCollection));\nio.listen(3000);\n')),(0,o.kt)("h3",{id:"usage-with-a-ttl-index"},"Usage with a TTL index"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'import { Server } from "socket.io";\nimport { createAdapter } from "@socket.io/mongo-adapter";\nimport { MongoClient } from "mongodb";\n\nconst DB = "mydb";\nconst COLLECTION = "socket.io-adapter-events";\n\nconst io = new Server();\n\nconst mongoClient = new MongoClient("mongodb://localhost:27017/?replicaSet=rs0");\n\nawait mongoClient.connect();\n\nconst mongoCollection = mongoClient.db(DB).collection(COLLECTION);\n\nawait mongoCollection.createIndex(\n  { createdAt: 1 },\n  { expireAfterSeconds: 3600, background: true }\n);\n\nio.adapter(createAdapter(mongoCollection, {\n  addCreatedAtField: true\n}));\n\nio.listen(3000);\n')),(0,o.kt)("h2",{id:"options"},"Options"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Name"),(0,o.kt)("th",{parentName:"tr",align:null},"Description"),(0,o.kt)("th",{parentName:"tr",align:null},"Default value"),(0,o.kt)("th",{parentName:"tr",align:null},"Added in"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"uid")),(0,o.kt)("td",{parentName:"tr",align:null},"the ID of this node"),(0,o.kt)("td",{parentName:"tr",align:null},"a random id"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"v0.1.0"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"requestsTimeout")),(0,o.kt)("td",{parentName:"tr",align:null},"the timeout for inter-server requests such as ",(0,o.kt)("inlineCode",{parentName:"td"},"fetchSockets()")," or ",(0,o.kt)("inlineCode",{parentName:"td"},"serverSideEmit()")," with ack"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"5000")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"v0.1.0"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"heartbeatInterval")),(0,o.kt)("td",{parentName:"tr",align:null},"the number of ms between two heartbeats"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"5000")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"v0.1.0"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"heartbeatTimeout")),(0,o.kt)("td",{parentName:"tr",align:null},"the number of ms without heartbeat before we consider a node down"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"10000")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"v0.1.0"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"addCreatedAtField")),(0,o.kt)("td",{parentName:"tr",align:null},"whether to add a ",(0,o.kt)("inlineCode",{parentName:"td"},"createdAt")," field to each MongoDB document"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"false")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"v0.2.0"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"changeStreamOptions")),(0,o.kt)("td",{parentName:"tr",align:null},"options to pass to the MongoDB change stream"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"{}")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"v0.4.0"))))),(0,o.kt)("h2",{id:"common-questions"},"Common questions"),(0,o.kt)("h3",{id:"do-i-still-need-to-enable-sticky-sessions-when-using-the-mongodb-adapter"}
1,"Do I still need to enable sticky sessions when using the MongoDB adapter?"),(0,o.kt)("p",null,"Yes. Failing to do so will result in HTTP 400 responses (you are reaching a server that is not aware of the Socket.IO session)."),(0,o.kt)("p",null,"More information can be found ",(0,o.kt)("a",{parentName:"p",href:"/docs/v4/using-multiple-nodes/"},"here"),"."),(0,o.kt)("h3",{id:"what-happens-when-the-mongodb-cluster-is-down"},"What happens when the MongoDB cluster is down?"),(0,o.kt)("p",null,"In case the connection to the MongoDB cluster is severed, the behavior will depend on the value of the ",(0,o.kt)("inlineCode",{parentName:"p"},"bufferMaxEntries")," option of the MongoDB client:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"if its value is ",(0,o.kt)("inlineCode",{parentName:"li"},"-1")," (default), the packets will be buffered until reconnection."),(0,o.kt)("li",{parentName:"ul"},"if its value is ",(0,o.kt)("inlineCode",{parentName:"li"},"0"),", the packets will only be sent to the clients that are connected to the current server.")),(0,o.kt)("p",null,"Documentation: ",(0,o.kt)("a",{parentName:"p",href:"http://mongodb.github.io/node-mongodb-native/3.6/api/global.html#MongoClientOptions"},"http://mongodb.github.io/node-mongodb-native/3.6/api/global.html#MongoClientOptions")),(0,o.kt)("h2",{id:"latest-releases"},"Latest releases"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Version"),(0,o.kt)("th",{parentName:"tr",align:null},"Release date"),(0,o.kt)("th",{parentName:"tr",align:null},"Release notes"),(0,o.kt)("th",{parentName:"tr",align:null},"Diff"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"0.4.0")),(0,o.kt)("td",{parentName:"tr",align:null},"August 2025"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/releases/tag/0.4.0"},"link")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/compare/0.3.2...0.4.0"},(0,o.kt)("inlineCode",{parentName:"a"},"0.3.2...0.4.0")))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"0.3.2")),(0,o.kt)("td",{parentName:"tr",align:null},"January 2024"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/releases/tag/0.3.2"},"link")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/compare/0.3.1...0.3.2"},(0,o.kt)("inlineCode",{parentName:"a"},"0.3.1...0.3.2")))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"0.3.1")),(0,o.kt)("td",{parentName:"tr",align:null},"January 2024"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/releases/tag/0.3.1"},"link")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/compare/0.3.0...0.3.1"},(0,o.kt)("inlineCode",{parentName:"a"},"0.3.0...0.3.1")))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"0.3.0")),(0,o.kt)("td",{parentName:"tr",align:null},"February 2023"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/releases/tag/0.3.0"},"link")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://github.com/socketio/socket.io-mongo-adapter/compare/0.2.1...0.3.0"},(0,o.kt)("inlineCode",{parentName:"a"},"0.2.1...0.3.0")))))),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://github.com/socketio/socket.io-mongo-adapter/blob/main/CHANGELOG.md"},"Complete changelog")),(0,o.kt)("h2",{id:"emitter"},"Emitter"),(0,o.kt)("p",null,"The MongoDB emitter allows sending packets to the connected clients from another Node.js process:"),(0,o.kt)(r.Z,{alt:"Diagram of how the MongoDB adapter works",sources:{light:(0,l.Z)("/images/mongo-emitter.png"),dark:(0,l.Z)("/images/mongo-emitter-dark.png")},mdxType:"ThemedImage"}),(0,o.kt)("h3",{id:"installation-1"},"Installation"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm install @socket.io/mongo-emitter mongodb\n")),(0,o.kt)("h3",{id:"usage-1"},"Usage"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'const { Emitter } = require("@socket.io/mongo-emitter");\nconst { MongoClient } = require("mongodb");
1\n\nconst mongoClient = new MongoClient("mongodb://localhost:27017/?replicaSet=rs0");\n\nconst main = async () => {\n  await mongoClient.connect();\n\n  const mongoCollection = mongoClient.db("mydb").collection("socket.io-adapter-events");\n  const emitter = new Emitter(mongoCollection);\n\n  setInterval(() => {\n    emitter.emit("ping", new Date());\n  }, 1000);\n}\n\nmain();\n')),(0,o.kt)("p",null,"Please refer to the cheatsheet ",(0,o.kt)("a",{parentName:"p",href:"/docs/v4/adapter/#emitter-cheatsheet"},"here"),"."))}u.isMDXComponent=!0}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.