A production-ready Go backend boilerplate using Fiber v3, following clean architecture principles with repository and service patterns.
project-root/
├── app/ # Application layer
│ ├── delivery/ # HTTP handlers (delivery layer)
│ ├── dto/ # Data Transfer Objects
│ │ ├── request/ # Request DTOs
│ │ └── response/ # Response DTOs
│ ├── repository/ # Data access layer
│ │ ├── repository.go # Repository interface
│ │ ├── user_repository.go # User data access
│ │ └── {entity}_repository.go
│ │
│ ├── services/ # Business logic layer
│ │ ├── service.go # Service interface
│ │ ├── user_service.go # User business logic
│ │ └── {entity}_service.go
│ │
│ ├── route/ # Route definitions
│ │ └── api.go # API routes registration
│ │
│ └── middleware/ # HTTP middleware
│ ├── auth.go # Authentication middleware
│ ├── logger.go # Logging middleware
│ └── cors.go # CORS middleware
│
├── bootstrap/ # Application bootstrap
│ └── app.go # App lifecycle & graceful shutdown logic
│
├── cmd/ # Application entrypoints
│ └── server/
│ └── main.go # Main API server entrypoint
│
├── config/ # Configuration files
│ ├── app.go # Application specific config
│ ├── config.go # Main config loader
│ ├── database.go # Database connection settings
│ └── logger.go # Logging settings
│
├── cores/ # Core framework components
│ ├── config.go # Core configuration structures
│ ├── contract.go # App contract & hook registration
│ ├── database.go # Database connection pool (pgx)
│ └── logger.go # Zap logger core initialization
│
├── spark-cli/ # Spark CLI source code
│ └── main.go # CLI implementation
│
├── spark # Spark CLI binary
├── logs/ # Application logs
├── tmp/ # Temporary build files
├── go.mod # Go module definition
├── go.sum # Go dependencies checksum
└── README.md # Project documentation
- Fiber v3 - Fast and lightweight HTTP framework
- Spark CLI - Custom CLI for dev server, migrations, and initialization
- Clean Architecture - Repository and service patterns
- Database - PostgreSQL with pgx/v5 for high-performance pooling
- Migrations - Integrated Tern support for database migrations
- Lifecycle Management - Built-in Graceful Shutdown & Hook system (Before/After)
- Logging - Production-grade Zap logger with configurable outputs
- Environment Driven - Configuration via environment variables
- Error Handling - Centralized error handling structure
- Response Format - Consistent API response structure
- Clone the repository using degit (recommended for a clean start) or git:
# Using degit
npx degit rachmanzz/fiber-starter my-project
cd my-project
# Or using git
git clone https://github.com/rachmanzz/fiber-starter.git my-project
cd my-project- Initialize the project (change module name):
# This will automatically update the module name in all files and go.mod
./spark init- Set up environment variables:
cp .env.example .env
# Edit .env with your configurationRun the API server with live reloading (Air):
./spark devSpark uses Tern for migrations. It will automatically install tern and initialize tern.conf if needed.
Run migrations:
./spark migrateCreate a new migration:
./spark migrate new create_users_tableThis project uses SQLC for type-safe database access.
- Define Queries: Place your SQL query files in the
queries/directory at the root (e.g.,queries/users.sql). - Configuration: To link your queries with the repository layer, ensure you have a
sqlc.yamlin the root with the following configuration:
version: "2"
sql:
- schema: "migrations" # or your schema path
queries: "queries"
engine: "postgresql"
gen:
go:
package: "repository"
out: "app/repository"
sql_package: "pgx/v5"- Generate Code: Run the following command to generate the Go code:
sqlc generateThe generated files will be placed in app/repository/, making them ready to be used by your services.
Fiber v3 is designed to be easily testable. This boilerplate follows Go's standard testing patterns combined with Fiber's built-in testing utilities.
Fiber v3 provides the app.Test method to simulate HTTP requests without starting a network server. This makes tests extremely fast.
Best Practices:
- Use
github.com/stretchr/testify/assertfor idiomatic assertions. - Use Dependency Injection to pass mock repositories or services into your handlers.
- Use Table-Driven Tests for comprehensive coverage.
Example Unit Test:
func TestUserHandler(t *testing.T) {
// 1. Setup
app := fiber.New()
mockRepo := new(MockUserRepository)
app.Get("/users/:id", handlers.GetUser(mockRepo))
// 2. Create Request
req, _ := http.NewRequest("GET", "/users/1", nil)
// 3. Perform Test
// In v3, Test takes (req, timeout_ms). Use -1 for no timeout.
resp, err := app.Test(req, -1)
// 4. Assertions
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
}For integration tests that require a real database, it is recommended to:
- Use a dedicated test database.
- Run migrations before tests using
./spark migrate. - Optionally use Testcontainers to spin up temporary PostgreSQL instances in Docker.
To run all tests:
go test ./..../spark init- Initialize the project with a new module name./spark dev- Run the application with live reloading using Air./spark migrate- Run database migrations./spark migrate new [name]- Create a new migration file./spark version- Print the version number of Spark
Run with Docker:
docker-compose up --buildThe boilerplate includes example routes. Check app/route/api.go for the default route configuration.
MIT License