All templates
Template8 min read

Node.js Template: Production-Ready Express API

A production-ready Node.js Express API template with OpenClaw deployment, health checks, error handling, and TypeScript.

A production-ready Node.js Express API template with everything you need to ship fast.

What's Included

  • Express.js — battle-tested web framework
  • TypeScript — catch errors before they happen
  • Zod — runtime validation for request/response
  • Winston — structured logging
  • Health check endpoint — for OpenClaw monitoring
  • Graceful shutdown — handle SIGTERM properly
  • Error handling — consistent error responses

Quick Start

mkdir my-app && cd my-app
npm init -y
npm install express typescript zod winston
npm install --save-dev @types/express ts-node-dev

Project Structure

my-app/
├── src/
│   ├── index.ts          # App entry point
│   ├── routes/
│   │   └── health.ts     # Health check route
│   ├── middleware/
│   │   ├── error.ts      # Error handler
│   │   └── validate.ts   # Zod validation
│   └── types/
│       └── index.ts      # Shared types
├── openclaw.json
├── tsconfig.json
└── package.json

src/index.ts

import express from 'express'
import { healthRouter } from './routes/health'
import { errorHandler } from './middleware/error'
import { validate } from './middleware/validate'
import { z } from 'zod'

const app = express()

app.use(express.json())
app.use(healthRouter)

// Example route with validation
app.post('/api/tasks',
  validate(z.object({ title: z.string().min(1) })),
  async (req, res) => {
    const task = await db.tasks.create({ data: req.body })
    res.json(task)
  }
)

app.use(errorHandler)

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

openclaw.json

{
  "name": "my-express-api",
  "runtime": "node",
  "port": 3000,
  "healthCheck": "/health"
}

Deploy with OpenClaw

openclaw deploy

That's it. OpenClaw:

  1. Detects Node.js + TypeScript
  2. Runs npm install
  3. Compiles TypeScript
  4. Starts with health checks
  5. Issues SSL certificate

Health Check Endpoint

// src/routes/health.ts
import { Router } from 'express'

export const healthRouter = Router()

healthRouter.get('/health', async (req, res) => {
  const dbOk = await checkDatabase()
  const redisOk = await checkRedis()

  if (!dbOk || !redisOk) {
    return res.status(503).json({
      status: 'degraded',
      checks: { db: dbOk, redis: redisOk }
    })
  }

  res.json({ status: 'ok', uptime: process.uptime() })
})

Error Handling

// src/middleware/error.ts
export function errorHandler(err: Error, req: express.Request, res: express.Response, next: express.NextFunction) {
  console.error({
    error: err.message,
    stack: err.stack,
    path: req.path,
    method: req.method
  })

  if (err instanceof ZodError) {
    return res.status(400).json({ error: 'Validation failed', details: err.errors })
  }

  res.status(500).json({ error: 'Internal server error' })
}

Deploy with EZClaw

If your backend supports an AI assistant, pair it with OpenClaw deployed via EZClaw. EZClaw handles the Fly.io provisioning — you keep your Node.js API wherever you like.

Skip the self-hosting

Deploy OpenClaw in under a minute

No servers. No SSH. No terminal. Pick a model, connect Telegram, and go.

Deploy free with Testflight