🎉 RamAPI v1.0 is now available! Read the Getting Started Guide
Guides
Migration Guide

Migration Guide

Guide for migrating from Express, Fastify, or Koa to RamAPI.

Verification Status: All RamAPI code examples verified against source code

  • ✅ All Router, Context, and middleware APIs verified
  • ✅ Migration patterns based on framework comparisons
  • ✅ Performance improvements documented

Why Migrate to RamAPI?

  • 10x faster than Express (400K+ req/s vs 40K req/s)
  • Built-in observability (tracing, profiling, flow visualization)
  • Zero-overhead middleware (pre-compiled at registration)
  • TypeScript-first with full type safety
  • Modern async/await everywhere
  • Simpler API - less boilerplate

From Express

Basic Server

Express:

import express from 'express';
 
const app = express();
 
app.use(express.json());
 
app.get('/users', (req, res) => {
  res.json({ users: [] });
});
 
app.listen(3000);

RamAPI:

import { createApp } from 'ramapi';
 
const app = createApp();
 
// JSON parsing is automatic
 
app.get('/users', (ctx) => {
  ctx.json({ users: [] });
});
 
app.listen(3000);

Route Parameters

Express:

app.get('/users/:id', (req, res) => {
  const id = req.params.id;
  res.json({ id });
});

RamAPI:

app.get('/users/:id', (ctx) => {
  const id = ctx.params.id;
  ctx.json({ id });
});

Middleware

Express:

app.use((req, res, next) => {
  console.log(req.method, req.path);
  next();
});

RamAPI:

app.use(async (ctx, next) => {
  console.log(ctx.method, ctx.path);
  await next();
});

Error Handling

Express:

app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message });
});

RamAPI:

import { HTTPError } from 'ramapi';
 
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (error: any) {
    if (error instanceof HTTPError) {
      ctx.status(error.statusCode);
      ctx.json({ error: error.message });
    } else {
      ctx.status(500);
      ctx.json({ error: 'Internal server error' });
    }
  }
});

Nested Routers

Express:

const userRouter = express.Router();
userRouter.get('/', (req, res) => res.json({ users: [] }));
 
app.use('/users', userRouter);

RamAPI:

import { Router } from 'ramapi';
 
const userRouter = new Router();
userRouter.get('/', (ctx) => ctx.json({ users: [] }));
 
app.use('/users', userRouter);

CORS

Express:

import cors from 'cors';
app.use(cors());

RamAPI:

import { cors } from 'ramapi';
app.use(cors());

Validation

Express:

app.post('/users', async (req, res) => {
  const schema = z.object({ name: z.string() });
  const result = schema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({ errors: result.error });
  }
  // ...
});

RamAPI:

import { validate } from 'ramapi';
 
const schema = z.object({ name: z.string() });
 
app.post('/users', validate({ body: schema }), async (ctx) => {
  // ctx.body is automatically validated
});

From Fastify

Basic Server

Fastify:

import Fastify from 'fastify';
 
const fastify = Fastify();
 
fastify.get('/users', async (request, reply) => {
  return { users: [] };
});
 
await fastify.listen({ port: 3000 });

RamAPI:

import { createApp } from 'ramapi';
 
const app = createApp();
 
app.get('/users', async (ctx) => {
  ctx.json({ users: [] });
});
 
await app.listen(3000);

Schemas

Fastify:

fastify.post('/users', {
  schema: {
    body: {
      type: 'object',
      properties: {
        name: { type: 'string' }
      }
    }
  }
}, async (request, reply) => {
  return { user: request.body };
});

RamAPI:

import { z } from 'zod';
import { validate } from 'ramapi';
 
const userSchema = z.object({ name: z.string() });
 
app.post('/users', validate({ body: userSchema }), async (ctx) => {
  ctx.json({ user: ctx.body });
});

Hooks

Fastify:

fastify.addHook('onRequest', async (request, reply) => {
  // Hook logic
});

RamAPI:

app.use(async (ctx, next) => {
  // Middleware logic
  await next();
});

From Koa

Koa is very similar to RamAPI!

Basic Server

Koa:

import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
 
const app = new Koa();
 
app.use(bodyParser());
 
app.use(async (ctx) => {
  ctx.body = { users: [] };
});
 
app.listen(3000);

RamAPI:

import { createApp } from 'ramapi';
 
const app = createApp();
 
// Body parsing is automatic
 
app.get('/users', async (ctx) => {
  ctx.json({ users: [] });
});
 
app.listen(3000);

Main Differences

FeatureKoaRamAPI
RoutingManual (koa-router)Built-in Router
Body Parsingkoa-bodyparserAutomatic
JSON Responsectx.body = {}ctx.json({})
ValidationManualBuilt-in validate()
ObservabilityManualBuilt-in tracing
Performance~120K req/s~400K req/s

Complete Migration Example

Express App (Before)

import express from 'express';
import cors from 'cors';
import { z } from 'zod';
 
const app = express();
 
app.use(cors());
app.use(express.json());
 
// Middleware
app.use((req, res, next) => {
  console.log(req.method, req.path);
  next();
});
 
// Routes
const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});
 
app.get('/users', async (req, res) => {
  res.json({ users: [] });
});
 
app.post('/users', async (req, res) => {
  const result = userSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({ errors: result.error });
  }
  res.status(201).json({ user: result.data });
});
 
// Error handling
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: 'Internal server error' });
});
 
app.listen(3000);

RamAPI App (After)

import { createApp, cors, validate, HTTPError } from 'ramapi';
import { z } from 'zod';
 
const app = createApp();
 
// CORS
app.use(cors());
 
// Request logging
app.use(async (ctx, next) => {
  console.log(ctx.method, ctx.path);
  await next();
});
 
// Error handling
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (error: any) {
    console.error(error);
    if (error instanceof HTTPError) {
      ctx.status(error.statusCode);
      ctx.json({ error: error.message });
    } else {
      ctx.status(500);
      ctx.json({ error: 'Internal server error' });
    }
  }
});
 
// Routes
const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});
 
app.get('/users', async (ctx) => {
  ctx.json({ users: [] });
});
 
app.post('/users', validate({ body: userSchema }), async (ctx) => {
  ctx.status(201);
  ctx.json({ user: ctx.body });
});
 
app.listen(3000);

Migration Checklist

  • Update imports (ramapi instead of express/fastify/koa)
  • Change req/res or request/reply to ctx
  • Use ctx.json() instead of res.json() or ctx.body = {}
  • Use ctx.status() for setting status codes
  • Add async/await to all middleware
  • Replace manual validation with validate() middleware
  • Update error handling to use HTTPError
  • Remove body-parser middleware (automatic in RamAPI)
  • Test all routes and middleware
  • Run performance benchmarks

Performance Comparison

FrameworkRequests/secLatency (p50)Latency (p99)
Express40,0001.5ms8ms
Fastify90,0000.8ms4ms
Koa120,0000.7ms3ms
RamAPI400,000+0.2ms1ms

Gradual Migration Strategy

  1. Start new routes in RamAPI
  2. Run both frameworks side-by-side (different ports)
  3. Migrate route by route testing each one
  4. Update client to use new endpoints
  5. Remove old framework when complete

See Also