Skip to content

Deploying a Meteor App

Meteor is a powerful, full-stack JavaScript platform for building modern web and mobile applications with ease. It combines a robust build system, real-time data synchronization between client and server, a comprehensive package ecosystem, and integrated deployment tools. With Meteor, you can build feature-rich applications in JavaScript from the frontend to the backend, making it an excellent choice for rapid development and scalable production applications.

This comprehensive guide walks you through deploying a Meteor application to Klutch.sh, covering both automatic Nixpacks-based deployments and Docker-based deployments. You’ll learn installation steps, explore sample code, configure environment variables, and discover best practices for production deployments.

Table of Contents

  • Prerequisites
  • Getting Started: Install Meteor
  • Sample Code Examples
  • Project Structure
  • Deploying Without a Dockerfile (Nixpacks)
  • Deploying With a Dockerfile
  • Environment Variables & Configuration
  • Database Configuration
  • Scaling & Performance Optimization
  • Troubleshooting
  • Resources

Prerequisites

To deploy a Meteor application on Klutch.sh, ensure you have:

  • Meteor CLI - Install from meteor.com/install
  • Node.js 18 or higher - For running your Meteor application
  • npm - For managing dependencies
  • Git - For version control
  • GitHub account - Klutch.sh integrates with GitHub for continuous deployments
  • Klutch.sh account - Sign up for free

Getting Started: Install Meteor

Create a New Meteor Project

Follow these steps to create and set up a new Meteor application:

  1. Install Meteor globally (if not already installed):
    Terminal window
    curl https://install.meteor.com/ | sh
  2. Create a new Meteor application:
    Terminal window
    meteor create my-meteor-app
    cd my-meteor-app
  3. Explore the generated project structure. Meteor creates a basic app with client and server directories.
  4. Start the development server:
    Terminal window
    meteor
  5. Visit http://localhost:3000 to see your app running. Meteor automatically rebuilds and reloads as you make changes.

Sample Code Examples

Basic Meteor Application with Collections

Here’s a complete example with a shared collection, client subscription, and server-side methods:

// lib/collections.js - Shared on both client and server
import { Mongo } from 'meteor/mongo';
export const Tasks = new Mongo.Collection('tasks');
server/main.js
import { Meteor } from 'meteor/meteor';
import { Tasks } from '../lib/collections';
Meteor.startup(() => {
// Create sample data if collection is empty
if (Tasks.find().count() === 0) {
Tasks.insert({ text: 'Welcome to Meteor on Klutch.sh!', createdAt: new Date() });
}
});
// Define methods
Meteor.methods({
'tasks.insert'(text) {
Tasks.insert({
text,
createdAt: new Date()
});
},
'tasks.remove'(taskId) {
Tasks.remove(taskId);
}
});
// Publish collection to clients
Meteor.publish('tasks', function () {
return Tasks.find();
});
client/main.js
import { Meteor } from 'meteor/meteor';
import { Tasks } from '../lib/collections';
Meteor.startup(() => {
// Subscribe to tasks
Meteor.subscribe('tasks');
});
// Client-side method call
function addTask(text) {
Meteor.call('tasks.insert', text, (error) => {
if (error) {
console.error(error);
} else {
console.log('Task added');
}
});
}

Meteor with MongoDB Integration

server/main.js
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
const Users = new Mongo.Collection('users');
Meteor.startup(() => {
// Check if collection has data
if (Users.find().count() === 0) {
Users.insert({
name: 'John Doe',
email: 'john@example.com',
createdAt: new Date()
});
}
});
// Method to get user data
Meteor.methods({
'users.getAll'() {
return Users.find().fetch();
},
'users.create'(userData) {
const id = Users.insert(userData);
return id;
}
});
// Publish user data
Meteor.publish('users', function() {
return Users.find({}, { fields: { email: 1, name: 1 } });
});

Meteor with Express Middleware

server/main.js
import { Meteor } from 'meteor/meteor';
import { WebApp } from 'meteor/webapp';
import express from 'express';
const app = express();
// Express middleware for API routes
app.use(express.json());
app.get('/api/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
app.post('/api/data', (req, res) => {
const { data } = req.body;
res.json({ received: data, processed: true });
});
// Mount Express app to Meteor WebApp
WebApp.connectHandlers.use(app);
Meteor.startup(() => {
console.log('Meteor server started');
});

Project Structure

A typical Meteor project has this structure:

my-meteor-app/
├── client/
│ ├── main.html
│ ├── main.js
│ └── components/
├── server/
│ └── main.js
├── lib/
│ ├── collections.js
│ └── methods.js
├── public/
│ └── images/
├── .meteor/
│ ├── packages
│ ├── platforms
│ └── versions
├── .gitignore
├── package.json
├── package-lock.json
└── README.md

Deploying Without a Dockerfile

Klutch.sh uses Nixpacks to automatically detect and build your Meteor application. This is the simplest deployment option that requires no additional configuration files.

  1. Before deploying, build your Meteor app for production to ensure everything compiles correctly:
    Terminal window
    meteor build ../my-meteor-app-build --server-only
  2. Push your Meteor application to a GitHub repository with all your source code, `.meteor` folder, `package.json`, and `package-lock.json` files.
  3. Log in to your Klutch.sh dashboard.
  4. Create a new project and give it a name (e.g., "My Meteor App").
  5. Create a new app with the following configuration:
    • Repository - Select your Meteor GitHub repository and the branch to deploy
    • Traffic Type - Select HTTP (for web applications serving HTTP traffic)
    • Internal Port - Set to 3000 (the default port for Meteor applications)
    • Region - Choose your preferred region for deployment
    • Compute - Select the appropriate compute resource size
    • Instances - Choose how many instances to run (start with 1 for testing)
    • Environment Variables - Add the following environment variables:
      • MONGO_URL - Your MongoDB connection string (e.g., mongodb+srv://username:password@cluster.mongodb.net/dbname)
      • METEOR_SETTINGS - JSON-encoded Meteor settings
      • Any other environment variables your app needs

    If you need to customize the start command or build process, you can set Nixpacks environment variables:

    • START_COMMAND: Override the default start command (e.g., node main.js)
    • BUILD_COMMAND: Override the default build command
  6. Click "Create" to deploy. Klutch.sh will automatically detect your Meteor project, install dependencies, build your app, and start the application.
  7. Once deployed, your app will be available at a URL like `example-app.klutch.sh`. Test it by visiting the URL in your browser.

Deploying With a Dockerfile

If you prefer more control over the build and runtime environment, you can use a Dockerfile. Klutch.sh will automatically detect and use any Dockerfile in your repository’s root directory.

  1. Create a `Dockerfile` in your project root:
    # Build stage
    FROM node:18-alpine AS builder
    WORKDIR /app
    # Copy source code
    COPY . .
    # Install Meteor
    RUN curl https://install.meteor.com/ | sh
    # Build Meteor app
    RUN meteor npm install
    RUN meteor build --server-only --directory /app/build
    # Production stage
    FROM node:18-alpine
    WORKDIR /app
    # Copy built app from builder
    COPY --from=builder /app/build/bundle /app/bundle
    WORKDIR /app/bundle/programs/server
    # Install production dependencies
    RUN npm install --production
    WORKDIR /app/bundle
    # Expose port
    EXPOSE 3000
    # Set environment variables
    ENV PORT=3000
    ENV NODE_ENV=production
    # Health check
    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD node -e "require('http').get('http://localhost:3000', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"
    # Start application
    CMD ["node", "main.js"]
  2. Create a `.dockerignore` file to exclude unnecessary files from the Docker build:
    node_modules
    .meteor/local
    .git
    .gitignore
    .DS_Store
    npm-debug.log
    .env
    .env.local
    .vscode
    .idea
    README.md
  3. Push your code (with Dockerfile and .dockerignore) to GitHub.
  4. Follow the same deployment steps as the Nixpacks method:
    • Log in to Klutch.sh
    • Create a new project
    • Create a new app pointing to your GitHub repository
    • Set the traffic type to HTTP and internal port to 3000
    • Add environment variables:
      • MONGO_URL - Your MongoDB connection string
      • METEOR_SETTINGS - JSON-encoded settings
      • Other required variables
    • Click “Create”

    Klutch.sh will automatically detect your Dockerfile and use it to build and deploy your application.

  5. Your deployed app will be available at `example-app.klutch.sh` once the build and deployment complete.

Environment Variables & Configuration

Meteor applications use environment variables for configuration. Set these in the Klutch.sh dashboard during app creation or update them afterward.

Common Environment Variables

# Server configuration
PORT=3000
NODE_ENV=production
# Database connection (critical for Meteor)
MONGO_URL=mongodb+srv://username:password@cluster.mongodb.net/dbname
# Meteor-specific settings
METEOR_SETTINGS={"public":{"apiUrl":"https://api.example.com"},"private":{"apiKey":"secret-key"}}
# Application settings
ROOT_URL=https://example-app.klutch.sh
MAIL_URL=smtp://user:password@mailhost.example.com:25
# Security
API_KEY=your_api_key_here
JWT_SECRET=your_jwt_secret_here
# Features
ENABLE_LOGGING=true
LOG_LEVEL=info

Using Environment Variables in Your App

server/main.js
import { Meteor } from 'meteor/meteor';
Meteor.startup(() => {
console.log('Running in environment:', process.env.NODE_ENV);
console.log('Root URL:', process.env.ROOT_URL);
// Access Meteor settings
const settings = Meteor.settings;
console.log('API URL:', settings.public.apiUrl);
});

Accessing Meteor Settings

// Both client and server can access public settings
if (Meteor.isClient) {
console.log('Public API URL:', Meteor.settings.public.apiUrl);
}
// Only server can access private settings
if (Meteor.isServer) {
console.log('Private API Key:', Meteor.settings.private.apiKey);
}

Database Configuration

Meteor applications typically use MongoDB. When deploying to Klutch.sh, you’ll need to configure a MongoDB connection.

Setting Up MongoDB Atlas

  1. Create a MongoDB Atlas account at mongodb.com/cloud/atlas
  2. Create a new cluster and database
  3. Create a database user with appropriate permissions
  4. Get your connection string (looks like: mongodb+srv://username:password@cluster.mongodb.net/dbname)
  5. Add the connection string as the MONGO_URL environment variable in Klutch.sh

Configuring Meteor for Production

Create a settings.json file for production settings:

{
"public": {
"apiUrl": "https://api.example.com",
"features": {
"analytics": true,
"notifications": true
}
},
"private": {
"apiKey": "secret-key",
"stripe": {
"secretKey": "sk_live_xxx"
}
}
}

Then set METEOR_SETTINGS environment variable to the JSON-encoded string of this file.


Scaling & Performance Optimization

Horizontal Scaling

Klutch.sh makes it easy to scale your Meteor application:

  • Multiple Instances - Set the number of instances in the app configuration to distribute traffic across multiple containers
  • Load Balancing - Klutch.sh automatically load balances traffic across all instances
  • Stateless Design - Ensure your application is stateless so it can run on multiple instances
  • Shared Database - Use MongoDB Atlas or similar managed database service for data consistency across instances

Performance Optimization Tips

  1. Minimize Publications - Only publish data that clients actually need
  2. Use Indexes - Create database indexes for frequently queried fields
  3. Implement Caching - Cache computed values and API responses
  4. Optimize Methods - Keep Meteor methods fast and focused
  5. Use Oplog - Configure MongoDB Oplog for faster reactive updates
  6. Monitor Resources - Track CPU, memory, and database usage
  7. Code Splitting - Use dynamic imports to reduce bundle size

Example with performance optimizations:

server/main.js
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
const Items = new Mongo.Collection('items');
// Create indexes for performance
Meteor.startup(() => {
Items.rawCollection().createIndex({ userId: 1, createdAt: -1 });
});
// Optimized publication - only send necessary fields
Meteor.publish('items', function(limit = 20) {
const userId = this.userId;
if (!userId) {
return this.ready();
}
return Items.find(
{ userId },
{
fields: { userId: 1, title: 1, createdAt: 1 },
sort: { createdAt: -1 },
limit
}
);
});
// Efficient method with proper error handling
Meteor.methods({
'items.create'(text) {
if (!this.userId) {
throw new Meteor.Error('not-authorized', 'Must be logged in');
}
return Items.insert({
userId: this.userId,
text,
createdAt: new Date()
});
}
});

Troubleshooting

Application Won’t Start

Problem - Deployment completes but the app shows as unhealthy

Solution:

  • Verify that your Meteor app builds locally: meteor build ../build --server-only
  • Check that package.json and .meteor/packages are properly configured
  • Ensure MONGO_URL environment variable is set correctly
  • Check application logs in the Klutch.sh dashboard
  • Verify that your app listens on port 3000 as configured

Build Fails During Deployment

Problem - Build process exits with errors

Solution:

  • Ensure all Meteor packages are in .meteor/packages
  • Check that dependencies in package.json are compatible with Node.js 18+
  • Verify that no local-only packages are being used
  • Remove any .meteor/local folder before pushing to GitHub
  • Test the build locally: meteor build ../build --server-only

Database Connection Issues

Problem - App starts but can’t connect to MongoDB

Solution:

  • Verify MONGO_URL environment variable is set and correct
  • Check MongoDB Atlas connection string format (should start with mongodb+srv://)
  • Ensure IP whitelist allows connections from Klutch.sh (use 0.0.0.0/0 or specific IPs)
  • Test MongoDB connection string locally
  • Check database user permissions

High Memory Usage

Problem - App uses excessive memory and gets killed

Solution:

  • Check for memory leaks in subscriptions and methods
  • Limit publication data with proper queries and field selectors
  • Implement pagination for large datasets
  • Monitor Oplog size if using Oplog for replication
  • Consider upgrading compute tier or reducing instance connections

Slow Reactive Updates

Problem - Changes don’t appear immediately on connected clients

Solution:

  • Enable MongoDB Oplog for faster reactive updates
  • Reduce publication data size
  • Use specific field projections in publications
  • Implement caching for frequently accessed data
  • Check database query performance with indexes

Resources


Summary

Deploying a Meteor application on Klutch.sh is straightforward whether you choose Nixpacks or Docker. Both methods provide reliable, scalable hosting for your full-stack JavaScript applications. Start with Nixpacks for simplicity and rapid deployments, or use Docker for complete control over your build environment. With Klutch.sh’s automatic scaling, load balancing, and environment variable management, you can deploy your Meteor app from development to production and scale it to serve thousands of users in real-time.