Skip to main content

Overview

This guide covers critical production configuration, security best practices, and performance optimization techniques for your Go + React scaffold application.

Security Best Practices

Environment Variables and Secrets

Never commit sensitive data to version control:
  • .env files containing secrets
  • API keys and credentials
  • Database passwords
  • JWT session keys

Session Key Security

The SESSION_KEY is used for JWT token signing. Generate a strong, cryptographically secure random key:
# Generate a secure random key
openssl rand -base64 32
Use this value for your SESSION_KEY environment variable in production.

Password Security

The scaffold uses bcrypt with a cost factor of 14 for password hashing:
// From backend/auth implementation
bcrypt.GenerateFromPassword([]byte(password), 14)
Bcrypt cost factor of 14 provides a good balance between security and performance. In 2026, this remains secure for most applications.

JWT Token Security

Best practices for JWT tokens:
  • Use strong signing algorithms (HS256 or RS256)
  • Set reasonable expiration times (e.g., 24 hours)
  • Implement token refresh mechanisms for longer sessions
  • Store tokens securely on the client (httpOnly cookies preferred over localStorage)
  • Validate tokens on every protected route

Input Validation

Always validate and sanitize user inputs to prevent injection attacks:
  • MongoDB query injection
  • XSS (Cross-Site Scripting)
  • SQL injection (if using SQL databases)
The Echo framework provides built-in validation:
// Validate inputs before processing
if err := c.Bind(&user); err != nil {
    return c.JSON(http.StatusBadRequest, map[string]string{
        "error": "Invalid input",
    })
}

// Validate required fields
if user.Email == "" || user.Password == "" {
    return c.JSON(http.StatusBadRequest, map[string]string{
        "error": "Email and password are required",
    })
}

MongoDB Query Safety

Sanitize MongoDB queries to prevent NoSQL injection:
// Use typed queries with bson.M
filter := bson.M{"email": email}

// Avoid directly interpolating user input into queries
// Bad: bson.M{"$where": userInput}
// Good: bson.M{"field": sanitizedInput}

CORS Configuration

Configure CORS properly for production. Do not use wildcard (*) origins in production.
Update your CORS middleware for production:
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
    AllowOrigins: []string{
        "https://yourfrontend.com",
        "https://app.yourfrontend.com",
    },
    AllowMethods: []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete},
    AllowHeaders: []string{"Authorization", "Content-Type"},
    AllowCredentials: true,
}))

HTTPS/TLS

Always use HTTPS in production. HTTP transmits data in plain text, exposing sensitive information.
Options for enabling HTTPS:
  1. Reverse Proxy (Recommended): Use nginx or Caddy to handle TLS termination
  2. Let’s Encrypt: Free SSL/TLS certificates
  3. Cloud Provider: Use built-in SSL/TLS (AWS ALB, Cloudflare, etc.)

Secure Session Cookies

If using cookies for authentication:
cookie := &http.Cookie{
    Name:     "session",
    Value:    token,
    HttpOnly: true,  // Prevent JavaScript access
    Secure:   true,  // Only send over HTTPS
    SameSite: http.SameSiteStrictMode, // CSRF protection
    MaxAge:   86400, // 24 hours
}
c.SetCookie(cookie)

Performance Optimization

Backend Performance

Database Connection Pooling

MongoDB driver handles connection pooling automatically. Configure for production:
clientOptions := options.Client().
    ApplyURI(mongoURI).
    SetMaxPoolSize(100).        // Max connections
    SetMinPoolSize(10).         // Min connections
    SetMaxConnIdleTime(60 * time.Second)

Context Timeouts

Always use context timeouts for database operations to prevent hanging requests:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

result := collection.FindOne(ctx, filter)
The scaffold currently uses context.TODO() - update to context.WithTimeout() for production.

Graceful Shutdown

Implement graceful shutdown to handle in-flight requests:
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)

go func() {
    if err := e.Start(":8080"); err != nil && err != http.ErrServerClosed {
        e.Logger.Fatal("shutting down the server")
    }
}()

<-quit
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

if err := e.Shutdown(ctx); err != nil {
    e.Logger.Fatal(err)
}

Frontend Performance

Build Optimization

Vite automatically optimizes production builds:
  • Code splitting
  • Tree shaking
  • Minification
  • Asset optimization

Lazy Loading

Implement code splitting for large applications:
import { lazy, Suspense } from 'react';

const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Dashboard />
    </Suspense>
  );
}

Asset Optimization

  • Compress images before deployment
  • Use WebP format for images
  • Enable gzip/brotli compression on your web server
  • Implement CDN for static assets

Monitoring and Logging

Backend Logging

Echo includes logging middleware:
e.Use(middleware.Logger())
For production, consider structured logging:
import "github.com/sirupsen/logrus"

log := logrus.New()
log.SetFormatter(&logrus.JSONFormatter{})
log.SetLevel(logrus.InfoLevel)

Error Tracking

Integrate error tracking services:
  • Sentry
  • Rollbar
  • Bugsnag
  • New Relic

Health Monitoring

Implement comprehensive health checks:
e.GET("/health", func(c echo.Context) error {
    // Check database connection
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    if err := db.Ping(ctx, nil); err != nil {
        return c.JSON(http.StatusServiceUnavailable, map[string]string{
            "status": "unhealthy",
            "reason": "database connection failed",
        })
    }
    
    return c.JSON(http.StatusOK, map[string]string{
        "status": "healthy",
        "version": "1.0.0",
    })
})

Environment-Specific Configuration

Use the APP_ENV variable to enable environment-specific behavior:
if os.Getenv("APP_ENV") == "production" {
    // Production-specific configuration
    e.Debug = false
    // Enable additional security middleware
    // Configure production logging
}

Database Backups

Implement regular database backups. Data loss can be catastrophic.

MongoDB Backup Strategies

  1. MongoDB Atlas: Automatic backups with point-in-time recovery
  2. mongodump: Manual backup utility
    mongodump --uri="mongodb://localhost:27017" --out=/backups/$(date +%Y%m%d)
    
  3. Replica Sets: Provide redundancy and high availability

Rate Limiting

Protect your API from abuse with rate limiting:
import "github.com/labstack/echo-contrib/middleware"

e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)))

Production Checklist

  • Environment variables configured securely
  • Strong SESSION_KEY generated
  • HTTPS/TLS enabled
  • CORS configured for production domains only
  • Database authentication enabled
  • Database backups configured
  • Context timeouts implemented
  • Graceful shutdown implemented
  • Logging and monitoring set up
  • Error tracking integrated
  • Rate limiting enabled
  • Health check endpoints implemented
  • Security headers configured
  • Input validation on all endpoints
  • Secrets not committed to version control

Next Steps

Deployment

Learn how to deploy your application

Coding Standards

Review code style guidelines and best practices

Build docs developers (and LLMs) love