Skip to content

Deploy to Node.js

Stoma runs natively on Node.js. Deploy to traditional servers, containers, or serverless platforms.

  1. Install dependencies

    Terminal window
    npm install hono @homegrower-club/stoma @hono/node-server
  2. Create your gateway

    For a minimal example, see the Basic Gateway partial. Here’s a typical production setup with the Node.js adapter:

    src/index.ts
    import {
    createGateway,
    cors,
    requestLog,
    rateLimit,
    } from "@homegrower-club/stoma";
    import { nodeAdapter } from "@homegrower-club/stoma/adapters/node";
    const gateway = createGateway(
    {
    name: "my-gateway",
    basePath: "/api",
    policies: [requestLog(), cors()],
    routes: [
    {
    path: "/users/*",
    pipeline: {
    policies: [rateLimit({ max: 100, window: 60 })],
    upstream: {
    type: "url",
    target: "https://api.example.com",
    rewritePath: (path) => path.replace("/api", ""),
    },
    },
    },
    ],
    },
    // Production adapter with rate limiting and caching support
    nodeAdapter()
    );
    export default gateway.app;
  3. Create the server entry

    src/server.ts
    import { createServer } from "@hono/node-server";
    import gateway from "./index";
    const port = parseInt(process.env.PORT || "3000");
    createServer({
    fetch: gateway.fetch,
    port,
    }).listen(() => {
    console.log(`Server running on http://localhost:${port}`);
    });
  4. Run

    Terminal window
    npx tsx src/server.ts

For production deployments, use the Node.js adapter:

src/index.ts
import {
createGateway,
cors,
rateLimit,
cache,
circuitBreaker,
} from "@homegrower-club/stoma";
import { nodeAdapter } from "@homegrower-club/stoma/adapters/node";
import { InMemoryMetricsCollector } from "@homegrower-club/stoma";
import { metricsReporter } from "@homegrower-club/stoma";
const adapter = nodeAdapter();
const metrics = new InMemoryMetricsCollector();
const gateway = createGateway({
name: "my-gateway",
basePath: "/api",
adapter,
policies: [
cors(),
metricsReporter({ collector: metrics }),
],
routes: [
{
path: "/users/*",
pipeline: {
policies: [
rateLimit({
max: 100,
windowSeconds: 60,
store: adapter.rateLimitStore,
}),
],
upstream: {
type: "url",
target: "https://api.example.com",
},
},
},
],
});
export default gateway.app;
export { gateway };

Best for simple deployments:

src/server.ts
import { createServer } from "@hono/node-server";
import gateway from "./index";
const server = createServer({
fetch: gateway.fetch,
port: 3000,
});
server.listen();

For integration with existing Express apps:

src/server.ts
import express from "express";
import { serve } from "@hono/node-server/serve";
import gateway from "./index";
const app = express();
app.use("*", serve({ fetch: gateway.app.fetch }));
app.listen(3000, () => {
console.log("Gateway listening on port 3000");
});

For better performance:

src/server.ts
import Fastify from "fastify";
import gateway from "./index";
const fastify = Fastify();
fastify.all("*", async (req, reply) => {
const response = await gateway.app.fetch(req.raw, {
// Pass any environment variables here
});
return response;
});
fastify.listen({ port: 3000 });
Terminal window
npm install -g pm2
Terminal window
# Start with cluster mode
pm2 start src/server.ts --name "stoma-gateway" --node-args "-r tsx"
# Or with ecosystem file
pm2 start ecosystem.config.js
ecosystem.config.js
module.exports = {
apps: [
{
name: "stoma-gateway",
script: "src/server.ts",
interpreter: "tsx",
env: {
NODE_ENV: "development",
PORT: 3000,
},
env_production: {
NODE_ENV: "production",
PORT: 8080,
},
instances: "max",
exec_mode: "cluster",
watch: false,
max_memory_restart: "500M",
autorestart: true,
restart_delay: 1000,
},
],
};
Terminal window
# Start
pm2 start ecosystem.config.js --env production
# View logs
pm2 logs stoma-gateway
# Restart
pm2 restart stoma-gateway
# Stop
pm2 stop stoma-gateway
# Monitor
pm2 monit

Use environment variables for configuration:

src/index.ts
const gateway = createGateway({
name: process.env.GATEWAY_NAME || "my-gateway",
basePath: process.env.BASE_PATH || "/api",
debug: process.env.DEBUG === "true",
// ...
});
Terminal window
# .env file
PORT=8080
GATEWAY_NAME=my-gateway
DEBUG=false
JWT_SECRET=your-secret
  • Use a process manager (PM2, systemd)
  • Set NODE_ENV=production
  • Configure health checks
  • Set up logging (JSON format recommended)
  • Use environment variables for secrets
  • Enable request logging with appropriate log levels
  • Configure appropriate timeouts