This document outlines recommended strategies for migrating from Node.js to Go services using the node-go-proxy middleware.
Start by migrating individual routes or services:
// Before: All in Node.js
app.use('/api/users', userRoutes);
app.use('/api/products', productRoutes);
app.use('/api/orders', orderRoutes);
// After: Gradual migration
app.use('/api/users', expressMiddlewareProxy({ port: 8080 })); // ✅ Migrated to Go
app.use('/api/products', productRoutes); // 🔄 Still in Node.js
app.use('/api/orders', orderRoutes); // 🔄 Still in Node.jsMigrate entire microservices:
// Route to different Go services
app.use('/api/users', expressMiddlewareProxy({ port: 8001 }));
app.use('/api/products', expressMiddlewareProxy({ port: 8002 }));
app.use('/api/orders', expressMiddlewareProxy({ port: 8003 }));Eventually replace the Node.js proxy with a proper load balancer (Nginx, HAProxy, etc.).
- Port handler functions first, then middleware
- No complete system rewrite required
- Validate functionality incrementally
- Minimize downtime and risk
- Route requests based on migration readiness
- Easy rollback if issues arise
- Mixed environment management
- A/B testing capabilities
- Isolate potential issues per route/module
- Quick revert or fix individual segments
- Maintain system stability during transition
- Incremental validation
Ensure shared states are properly handled:
// Centralized session management
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET
}));
// Both Node.js and Go services can access Redis
app.use('/api/users', expressMiddlewareProxy({
port: 8080,
headers: {
'x-session-id': req.sessionID
}
}));Monitor latency and performance:
app.use('/api', expressMiddlewareProxy(
{ port: 8080 },
async (req, res, data) => {
// Track performance metrics
const endTime = Date.now();
const duration = endTime - req.startTime;
await metrics.track({
route: req.url,
method: req.method,
statusCode: res.statusCode,
duration: duration,
responseSize: data.length
});
}
));Implement comprehensive testing:
// Integration tests for proxy behavior
describe('User API Proxy', () => {
it('should proxy POST requests correctly', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'John Doe' })
.expect(201);
expect(response.body).toMatchObject({
id: expect.any(Number),
name: 'John Doe'
});
});
it('should handle file uploads', async () => {
const response = await request(app)
.post('/api/users/avatar')
.attach('file', 'test/fixtures/avatar.jpg')
.expect(200);
});
});Maintain security across services:
// Ensure CORS, rate limiting, etc. are consistent
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(','),
credentials: true
}));
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
}));
// Then apply proxy
app.use('/api', expressMiddlewareProxy({ port: 8080 }));// Wrong - writes response twice
pres.on("data", (chunk) => {
chunks.push(chunk);
ores.write(chunk); // ❌ Don't do this with callbacks
});
// Correct - buffer then write
pres.on("data", (chunk) => {
chunks.push(chunk); // ✅ Just buffer
});// Add proper error handling
app.use('/api', expressMiddlewareProxy(
{ port: 8080 },
async (req, res, data) => {
try {
await processData(data);
} catch (error) {
console.error('Processing error:', error);
// Handle gracefully
}
}
));// Ensure proper content-type handling
if (contentType.includes("multipart/form-data")) {
// Handle file uploads
} else if (contentType.includes("application/json")) {
// Handle JSON
} else {
// Handle other types
}- Set up monitoring and logging
- Implement health checks for Go services
- Create rollback procedures
- Test proxy middleware thoroughly
- Migrate one route/service at a time
- Monitor performance and error rates
- Validate data consistency
- Test edge cases (file uploads, large payloads)
- Remove unused Node.js code
- Update documentation
- Optimize Go service performance
- Plan infrastructure migration (Nginx/HAProxy)
- Implement proxy middleware
- Set up Go development environment
- Create monitoring dashboard
- Migrate user authentication service
- Implement comprehensive testing
- Monitor for 1 week
- Migrate user management
- Migrate product catalog
- Migrate order processing
- Performance tuning
- Infrastructure planning
- Documentation updates
- Set up Nginx/HAProxy
- Remove Node.js proxy layer
- Final testing and monitoring
This migration strategy provides a safe, incremental path from Node.js to Go while maintaining system reliability and minimizing risk. The key is patience, thorough testing, and comprehensive monitoring throughout the process.