A production-ready Go web service boilerplate built with Fiber framework, featuring OpenAPI-based code generation, PostgreSQL integration, and a clean, modular architecture.
- High-Performance Web Framework: Built on Fiber (powered by fasthttp)
- OpenAPI-First Development: API definitions drive code generation with
oapi-codegen - Type-Safe Database Access: SQL code generation with sqlc
- JWT Authentication: Secure token-based authentication with automatic validation
- Session Management: Two-tier caching strategy (in-memory + database)
- Graceful Shutdown: Proper cleanup and connection handling
- Structured Logging: Using zerolog for performance and clarity
- CORS Support: Configurable cross-origin resource sharing
- Auto-generated API Validation: Request/response validation via OpenAPI middleware
- Go: 1.24.4
- Web Framework: Fiber v2 - Express-inspired web framework
- Database: PostgreSQL with sqlx
- Cache: Ristretto (high-performance) / go-cache (simple)
- Logging: zerolog - Zero allocation JSON logger
- JWT: golang-jwt/jwt v5
- Password/Token Storage: Secure environment variable management
- OpenAPI Generator: oapi-codegen v2
- SQL Code Generator: sqlc
- Environment Variables: caarlos0/env
- Dotenv: joho/godotenv
- Null Types: guregu/null
Before you begin, ensure you have the following installed:
- Go: 1.24.4 or higher
- PostgreSQL: 12 or higher
- Node.js & npm: For OpenAPI tools (swagger-cli)
- Make: For build automation
-
sqlc: SQL code generator
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
-
oapi-codegen: OpenAPI code generator
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
-
swagger-cli: OpenAPI validation and bundling
npm install -g @apidevtools/swagger-cli
git clone <repository-url>
cd fiber-boilerplatego mod downloadcreatedb playgroundpsql -U postgres -d playground -f database/V0__init.sqlOr connect to your PostgreSQL instance and run:
\i database/V0__init.sqlCopy the example environment file:
cp .env.example .envEdit .env with your configuration:
# Application Configuration
PORT=8080
ENV=local # Options: local, development, production
# PostgreSQL Configuration
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password_here
DB_NAME=playground
DB_MAX_IDLE_CONNS=5
DB_MAX_OPEN_CONNS=100
DB_MAX_LIFETIME=300
# Redis Configuration (Optional)
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# JWT Configuration (REQUIRED)
JWT_SECRET=your_secure_random_secret_here
# CORS Configuration (Optional)
CORS_ENABLED=true
CORS_ALLOW_ORIGINS=*
CORS_ALLOW_METHODS=GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS
# Graceful Shutdown (Optional)
GRACEFUL_TIMEOUT=10 # seconds
LOG_REQUESTS_ENABLED=trueImportant: Change JWT_SECRET to a secure random string in production!
Generate OpenAPI and sqlc code:
make openapi # Validates, bundles, and generates OpenAPI code
make sqlc # Generates database models from SQLmake buildThe compiled binary will be in out/fiber-boilerplate.
make run-mainOr run the binary directly:
./out/fiber-boilerplateSet ENV=production in your .env file or environment:
ENV=production ./out/fiber-boilerplateOnce the server is running (default: http://localhost:8080):
curl http://localhost:8080/api/pingExpected response:
{
"code": 200,
"message": "OK",
"data": {
"message": "pong"
}
}curl -X POST http://localhost:8080/api/appuser/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"name": "John Doe",
"birthday": "1990-01-01",
"gender": "M"
}'curl -X GET "http://localhost:8080/api/appuser/list?limit=10&page=1" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"For development, you have two options:
Generate a JWT token with the included utility (valid for 7 days):
go run generate_jwt.goThis generates a token with:
uuid: Sample user UUID (12956e54-503d-46f1-8b9b-7cf304fba601)exp: 7 days from now (auto-calculated)iat: Current timestamp (auto-calculated)
Use online tools like jwt.io or create tokens programmatically.
JWT Payload Format:
{
"uuid": "your-user-uuid-here",
"exp": 1735689600,
"iat": 1735344000
}Required fields:
uuid(string): User UUIDexp(integer): Unix timestamp when token expires
Optional fields:
iat(integer): Unix timestamp when token was issued
Signing:
- Algorithm: HS256
- Secret: Your
JWT_SECRETvalue from.env
# Main entry point
vim api/index.yaml
# Schemas
vim api/schemas.yaml
# Endpoints
vim api/v1/create_appuser.yamlmake openapiThis will:
- Validate OpenAPI specs
- Bundle into
out/openapi.yaml - Generate Go code in
internal/generated/serviceapi/
vim database/V0__init.sqlvim database/queries/appuser.sqlmake sqlc# Run tests
make test
# Build
make build
# Run all (test + build)
make all
# Clean build artifacts
make cleanAll API endpoints are prefixed with /api and defined in OpenAPI specifications.
GET /api/ping- Health check (no authentication required)
POST /api/appuser/create- Create a new userGET /api/appuser/list- List users with pagination and filteringPUT /api/appuser/update- Update an existing user
uuid(string) - Filter by user UUIDname(string) - Filter by namegender(string) - Filter by gender (M/F)withdraw(boolean) - Filter by withdrawal statuslimit(integer) - Items per page (max: 1000)page(integer) - Page number (1-based)sorting[key](string) - Sort fieldsorting[dir](string) - Sort direction (asc/desc)
fiber-boilerplate/
├── cmd/
│ └── main.go # Application entry point
├── internal/
│ ├── app/
│ │ ├── app.go # Application startup and shutdown
│ │ ├── config/ # Configuration management
│ │ ├── handlers/ # HTTP request handlers
│ │ │ └── v1/ # API v1 handlers
│ │ ├── middleware/ # Fiber middleware
│ │ └── router/ # Route definitions
│ ├── pkg/
│ │ ├── cache/ # Cache implementations
│ │ ├── database/ # Database drivers
│ │ ├── logging/ # Logging utilities
│ │ ├── session/ # Session management
│ │ ├── setting/ # Runtime settings
│ │ └── util/ # Utility functions
│ ├── models/ # Generated database models (sqlc)
│ ├── generated/ # Generated OpenAPI code
│ └── defs/ # Error definitions
├── api/ # OpenAPI specifications
│ ├── index.yaml # Main spec entry point
│ ├── schemas.yaml # Data schemas
│ ├── parameters.yaml # Reusable parameters
│ └── v1/ # API v1 endpoint specs
├── database/
│ ├── V0__init.sql # Database schema
│ └── queries/ # SQL query definitions
│ └── appuser.sql
├── sqlc_conf/
│ ├── sqlc.yaml # sqlc configuration
│ └── overrides.yaml # Field name overrides
├── build/ # Makefile modules
│ ├── common.mk
│ ├── go.mk
│ └── openapi.mk
├── out/ # Build artifacts (gitignored)
├── .env.example # Environment template
├── go.mod # Go dependencies
├── Makefile # Build automation
├── CLAUDE.md # AI assistant guidelines
├── LICENSE # MIT License
└── README.md # This file
Requests flow through middleware in this order:
- Request ID - Unique request tracking
- Logger - Request/response logging
- Recover - Panic recovery
- ETag - HTTP caching
- Compress - Response compression
- Pprof - Profiling (local/dev only)
- CORS - Cross-origin resource sharing
- OpenAPI Validation - Request validation and auth requirement detection
- JWT Authentication (keyauth) - Bearer token extraction and validation
- Session - User session loading from database
All tables follow a standard pattern:
CREATE TABLE example (
id bigserial PRIMARY KEY,
uuid uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
created_at timestamptz NOT NULL DEFAULT now(),
modified_at timestamptz NOT NULL DEFAULT now(),
-- domain-specific fields --
);
-- Auto-update modified_at on every UPDATE
CREATE TRIGGER tr_example_update_modified_at
BEFORE UPDATE ON example
FOR EACH ROW EXECUTE PROCEDURE fn_set_modified_at();// In Fiber handlers, use ctx.Context() to convert *fiber.Ctx to context.Context
result, err := models.Appuser.CreateAppuser(nil, ctx.Context(), params)// Get context.Context from Fiber context
tx, qctx, err := models.SQL.BeginxContext(ctx.Context())
if err != nil {
return err
}
defer tx.Rollback()
qtx := models.New(tx)
result, err := models.Appuser.UpdateAppuser(qtx, qctx, params)
if err != nil {
return err
}
return tx.Commit()| Variable | Default | Description |
|---|---|---|
PORT |
8080 | HTTP server port |
ENV |
local | Environment (local/development/production) |
JWT_SECRET |
required | JWT signing secret |
GRACEFUL_TIMEOUT |
10 | Graceful shutdown timeout (seconds) |
LOG_REQUESTS_ENABLED |
true | Enable request logging |
DB_HOST |
localhost | PostgreSQL host |
DB_PORT |
5432 | PostgreSQL port |
DB_USER |
postgres | Database user |
DB_PASSWORD |
"" | Database password |
DB_NAME |
playground | Database name |
DB_MAX_IDLE_CONNS |
5 | Max idle connections |
DB_MAX_OPEN_CONNS |
100 | Max open connections |
DB_MAX_LIFETIME |
300 | Connection lifetime (seconds) |
REDIS_HOST |
localhost | Redis host |
REDIS_PORT |
6379 | Redis port |
REDIS_PASSWORD |
"" | Redis password |
CORS_ENABLED |
true | Enable CORS |
CORS_ALLOW_ORIGINS |
* | Allowed origins (comma-separated) |
CORS_ALLOW_METHODS |
GET,HEAD,PUT,... | Allowed HTTP methods |
CORS_ALLOW_HEADERS |
"" | Allowed headers |
CORS_ALLOW_CREDENTIALS |
false | Allow credentials |
CORS_EXPOSE_HEADERS |
"" | Exposed headers |
CORS_MAX_AGE |
0 | Preflight cache duration (seconds) |
make all # Run tests and build
make build # Compile application
make run-main # Run the application
make test # Run tests
make tidy # Tidy Go modules
make clean # Remove build artifacts
make openapi # OpenAPI workflow (validate + bundle + generate)
make openapi-validate # Validate OpenAPI specs
make openapi-bundle # Bundle OpenAPI specs
make openapi-generate # Generate Go code from OpenAPI
make sqlc # Generate database models- Verify PostgreSQL is running:
pg_isready - Check connection settings in
.env - Ensure database exists:
psql -l | grep playground
- Install swagger-cli:
npm install -g @apidevtools/swagger-cli - Validate specs manually:
make openapi-validate
- Install sqlc:
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest - Check
database/queries/*.sqlsyntax
- Ensure
JWT_SECRETis set in.env - Verify token format (Bearer scheme)
- Check token expiration (
expclaim)
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For issues and questions:
- Open an issue on GitHub
- Check existing documentation in
CLAUDE.md - Review OpenAPI specs in
api/directory
- Fiber - Web framework
- sqlc - SQL code generator
- oapi-codegen - OpenAPI code generator
- zerolog - Logging library