Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/meteor/meteor/llms.txt

Use this file to discover all available pages before exploring further.

DDP Connections API

DDP (Distributed Data Protocol) is Meteor’s protocol for sending data over WebSockets. These APIs allow you to manage connections and create multi-server applications. Source: packages/ddp-client/common/livedata_connection.js

DDP.connect()

Connect to another Meteor server and return a connection object. Locus: Anywhere
url
string
required
URL of another Meteor application to connect to.
options
object
Optional connection options.
reloadWithOutstanding
boolean
Whether to reload if there are outstanding methods. Default: false.
headers
object
Extra headers to send on the WebSocket connection (server-to-server DDP only).
retry
boolean
Whether to automatically retry on connection failures. Default: true.
onDDPVersionNegotiationFailure
function
Callback when version negotiation fails.
import { DDP } from 'meteor/ddp-client';

// Connect to another Meteor server
const remoteConnection = DDP.connect('http://example.com');

// With options
const connection = DDP.connect('https://api.example.com', {
  retry: true,
  headers: {
    'X-API-Key': 'secret-key'
  }
});

Connection Object

The connection object returned by DDP.connect() has the same API as Meteor on the client:

connection.subscribe()

Subscribe to a publication on the remote server.
const handle = remoteConnection.subscribe('posts', { limit: 10 });

if (handle.ready()) {
  console.log('Remote data loaded');
}

connection.call() / connection.callAsync()

Call a method on the remote server.
// Callback style
remoteConnection.call('insertPost', title, content, (error, result) => {
  if (error) {
    console.error('Remote method failed:', error);
  } else {
    console.log('Post created:', result);
  }
});

// Async style
try {
  const postId = await remoteConnection.callAsync(
    'insertPost',
    title,
    content
  );
  console.log('Post created:', postId);
} catch (error) {
  console.error('Failed:', error);
}

connection.apply() / connection.applyAsync()

Call a method with an array of arguments.
const args = [title, content, tags];

await remoteConnection.applyAsync('insertPost', args, {
  wait: true
});

connection.status()

Get the current connection status. A reactive data source. Returns: Object with status information
connected
boolean
True if currently connected to the server.
status
string
Connection status: “connected”, “connecting”, “failed”, “waiting”, or “offline”.
retryCount
number
Number of reconnection attempts made.
retryTime
number
Estimated time of next reconnection attempt.
reason
string
If failed, description of why the connection failed.
const status = remoteConnection.status();

if (status.connected) {
  console.log('Connected to remote server');
} else {
  console.log('Status:', status.status);
  if (status.retryTime) {
    console.log('Retrying at:', new Date(status.retryTime));
  }
}

// Reactive usage
Tracker.autorun(() => {
  const status = remoteConnection.status();
  console.log('Connection status changed:', status.status);
});

connection.reconnect()

Force an immediate reconnection attempt.
remoteConnection.reconnect();

connection.disconnect()

Disconnect from the server.
remoteConnection.disconnect();

connection.close()

Permanently close the connection.
remoteConnection.close();

connection.userId()

Get the user ID on this connection. A reactive data source.
const userId = remoteConnection.userId();
if (userId) {
  console.log('Logged in on remote connection:', userId);
}

Using Remote Collections

Access collections from a remote server:
import { Mongo } from 'meteor/mongo';

// Create connection to remote server
const remoteConnection = DDP.connect('https://api.example.com');

// Create collection using remote connection
const RemotePosts = new Mongo.Collection('posts', {
  connection: remoteConnection
});

// Subscribe to data from remote server
remoteConnection.subscribe('posts');

// Query remote collection
const posts = RemotePosts.find().fetch();
console.log('Posts from remote server:', posts);

// Insert into remote collection
RemotePosts.insert({ 
  title: 'Hello Remote World',
  content: 'Posted via DDP connection'
});

Server-to-Server Connections

Connect Meteor servers to each other:
// Server A: Expose methods
Meteor.methods({
  'serverA.getData'() {
    return SomeCollection.find().fetch();
  }
});

// Server B: Connect to Server A
if (Meteor.isServer) {
  const serverA = DDP.connect('http://server-a.example.com', {
    headers: {
      'X-Server-Key': process.env.SERVER_KEY
    }
  });
  
  // Call method on Server A
  Meteor.methods({
    async 'getDataFromServerA'() {
      return await serverA.callAsync('serverA.getData');
    }
  });
}

Connection Lifecycle Events

Listen to connection events:
// On the default connection (Meteor.connection)
Meteor.connection._stream.on('reset', () => {
  console.log('Connection reset');
});

Meteor.connection._stream.on('disconnect', () => {
  console.log('Disconnected from server');
});

// On custom connection
remoteConnection._stream.on('message', (message) => {
  console.log('Received message:', message);
});

DDP.onReconnect()

Register a callback to be called on reconnect.
DDP.onReconnect((conn) => {
  console.log('Reconnected to server');
  
  // Re-fetch data or reset state
  if (conn === Meteor.connection) {
    console.log('Main connection reconnected');
  }
});

Meteor.onConnection() (Server)

Register a callback to be called when a new DDP connection is made to the server. Locus: Server
callback
function
required
The function to call when a new DDP connection is established.
Meteor.onConnection((connection) => {
  console.log('New connection:', connection.id);
  console.log('Client address:', connection.clientAddress);
  console.log('HTTP headers:', connection.httpHeaders);
  
  connection.onClose(() => {
    console.log('Connection closed:', connection.id);
  });
});

Connection Object Properties (Server)

id
string
Globally unique identifier for this connection.
close
function
Close this DDP connection. The client will reconnect.
onClose
function
Register a function to be called when this connection is closed.
clientAddress
string
The IP address of the client.
httpHeaders
object
HTTP headers sent by the client in the initial WebSocket handshake.

Multi-Server Architecture Example

// API Server (server/main.js)
import { Meteor } from 'meteor/meteor';

Meteor.methods({
  'api.getUsers'() {
    return Meteor.users.find({}, {
      fields: { username: 1, emails: 1 }
    }).fetch();
  },
  
  'api.createUser'(userData) {
    check(userData, Object);
    return Accounts.createUserAsync(userData);
  }
});

// Web Server (server/main.js)
import { DDP } from 'meteor/ddp-client';

const apiServer = DDP.connect('https://api.myapp.com', {
  headers: {
    'X-API-Key': Meteor.settings.apiKey
  }
});

Meteor.methods({
  async 'getUsers'() {
    // Proxy to API server
    return await apiServer.callAsync('api.getUsers');
  },
  
  async 'createUser'(userData) {
    return await apiServer.callAsync('api.createUser', userData);
  }
});

// Client code remains the same
Meteor.call('getUsers', (error, users) => {
  if (!error) {
    console.log('Users:', users);
  }
});

Best Practices

  1. Connection Pooling: Reuse connections instead of creating new ones for each request.
  2. Error Handling: Always handle connection failures gracefully.
const connection = DDP.connect(url);

Tracker.autorun(() => {
  const status = connection.status();
  if (status.status === 'failed') {
    console.error('Connection failed:', status.reason);
    // Show error to user
  }
});
  1. Security: Use authentication for server-to-server connections.
const connection = DDP.connect(url, {
  headers: {
    'Authorization': 'Bearer ' + serverToken
  }
});
  1. Cleanup: Close connections when no longer needed.
// In component unmount or route leave
remoteConnection.disconnect();