Self-hosted service
create-go-app/fiber-go-template avatar
create-go-app/fiber-go-template

fiber-go-template, a backend skeleton where the folders tell you where to put things

📝 Production-ready backend template with Fiber Go Web Framework for Create Go App CLI.

1,118 stars153 forksGoApache-2.0

At a glance

What is it?
fiber-go-template is the Fiber backend template for the Create Go App CLI: a Go 1.24 service with PostgreSQL, Redis, JWT, Swagger docs and a Docker Makefile. Its real contribution is the folder layout, which separates business logic from platform plumbing.
Who is it for?
Adopt fiber-go-template if you want a Go API that starts with sensible answers for the boring decisions, namely folder layout, environment configuration, database and cache wiring, migrations, JWT and generated API docs, and you plan to own the code afterwards. Do not adopt it if you want a framework with an upgrade path, since the tagged releases stop at v1.14.0 from 2022-06-01 and the template ships placeholder secrets such as JWT_SECRET_KEY="secret" that you must change.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 176 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A skeleton with a fixed answer for the boring decisions

fiber-go-template is the Fiber backend template for the Create Go App CLI, described as a production-ready backend template. The web framework in use is Fiber, which the project description characterises as an Express.js inspired framework built on top of Fasthttp, with an emphasis on fast development, zero memory allocation and performance.

The value of a template like this is not the framework, it is the set of decisions it has already made. Which database, which cache, how the environment is read, where migrations live, how the API docs are generated, how the container image is built. A team that would otherwise spend its first two days on those choices gets them answered, with the reasoning already written into the folder structure.

It is a template in the literal sense, though. There is no runtime magic and no plugin system, and the project is Apache 2.0 licensed, which means what you get is a directory of Go files that you copy into your repository and then own completely.

The audience is developers starting a Go API who want a working stack, not a framework author. The Create Go App CLI generates a project from it, and the template is also usable on its own since it is a normal Go module with a main.go at the root.

app, pkg, platform and docs: four folders, four responsibilities

The folder layout is the part of this template worth studying, because it is a stated opinion about where code belongs rather than an accident of history.

The app directory holds business logic only. The description is explicit that this directory does not care what database driver you use or which caching solution you choose, or any third-party thing. Inside it, controllers for the functional routes, models describing the business models and their methods, and queries describing the queries for those models.

The pkg directory holds project-specific functionality: the configuration functions, the middleware, both Fiber built in and your own, the repository folder for the constants of the project, the routes, and utilities such as the server starter and an error checker.

The platform directory holds platform level logic, the part that actually builds up the project: setting up the database, the cache server instance and storing migrations. The database setup defaults to PostgreSQL, the cache setup defaults to Redis and is described as in-memory, and the migrations folder is where the migration files live for the golang-migrate tool.

The docs directory holds the configuration for the auto-generated API documentation.

Read that way, the rule is simple. Business rules go in app, wiring goes in pkg, and everything that touches a specific external system goes in platform. It is a small idea that makes a large codebase navigable.

make docker.run starts Postgres, Redis and the API together

The quick start is short. You create the project with the CLI, choose fiber as the backend framework, rename .env.example to .env, install Docker and a handful of Go tools, and then run the project.

The creation step is the CLI's own command, and the framework choice is made interactively.

bash
cgapp create

# Choose a backend framework:
#   net/http
# > fiber
#   chi

Then the run command, which is a Makefile target rather than a docker compose invocation.

bash
make docker.run

That target is worth reading in the Makefile, because it shows the whole development stack being assembled from nothing. It depends on docker.network, which creates a bridge network called dev-network if it does not already exist, on docker.postgres, which runs a postgres container named cgapp-postgres with a volume bound into the home directory, on swag to regenerate the API documentation, on docker.fiber, which builds the image and runs it as cgapp-fiber with port 5000 published, on docker.redis, running a redis container, and finally on migrate.up, which applies the pending migrations.

So one make target brings up a database, a cache, the migrations and the API, on a private network, with the API reachable on port 5000. There are matching docker.stop targets for each container, and the make test target is what you would run before any of it.

The .env file is the contract, and its defaults are placeholders

Configuration is read from a .env file, and the repository ships .env.example and .env.test with the same shape. The example file is the fastest way to see everything the service expects.

ini
# Stage status to start server:
#   - "dev", for start server without graceful shutdown
#   - "prod", for start server with graceful shutdown
STAGE_STATUS="dev"

# Server settings:
SERVER_HOST="0.0.0.0"
SERVER_PORT=5000
SERVER_READ_TIMEOUT=60

# JWT settings:
JWT_SECRET_KEY="secret"
JWT_SECRET_KEY_EXPIRE_MINUTES_COUNT=15
JWT_REFRESH_KEY="refresh"
JWT_REFRESH_KEY_EXPIRE_HOURS_COUNT=720

The first key is the one that changes behaviour rather than just values. STAGE_STATUS decides whether the server starts with a graceful shutdown path or without one, and the two allowed values are dev and prod.

Below that, the database block is written to cover two drivers with one set of keys, with DB_TYPE set to pgx and a comment that it can be pgx or mysql, the host defaulting to the cgapp-postgres container name, a pool configuration with maximum connections, maximum idle connections and a maximum lifetime, and an SSL mode setting. The Redis block follows with host, port, password and database number.

The defaults are development placeholders, and one of them is a security problem if you forget it. JWT_SECRET_KEY is the literal string secret and the refresh key is refresh, with an access token lifetime of 15 minutes and a refresh lifetime of 720 hours. Copy the example file as instructed, then change those two values before anything is reachable from outside your machine.

A scratch image with a statically linked binary

The Dockerfile is a two stage build that ends in a scratch image, which is the current best practice for a Go service and the reason the image is small.

The builder stage uses a golang Alpine image, copies go.mod and go.sum, runs go mod download so the dependency layer is cached, copies the source, sets CGO_ENABLED=0 with GOOS and GOARCH for Linux on amd64, and builds with the linker flags -s -w to strip the symbol table and debug information into a binary called apiserver.

The final stage is FROM scratch, which means an empty filesystem with no shell, no package manager and no libc. Into it the binary and the .env file are copied, and the entrypoint is the apiserver itself.

That last detail has a consequence worth flagging. Copying the .env into the image bakes the configuration into the container, so the environment file is a build input rather than a runtime input. That is convenient for a local development stack where the file is a placeholder anyway, and it is a problem for a deployment pipeline where you would rather inject configuration at run time, because the image then carries whatever secrets were present at build time. The project does not document an override for this, so the choice is yours to make deliberately.

The static build is also what makes the scratch stage possible, since CGO is disabled and nothing dynamic has to be present in the final filesystem.

The Makefile makes the quality gate a dependency, not a habit

The test target in the Makefile is the line that tells you what this project values.

bash
test: clean critic security lint
	go test -v -timeout 30s -coverprofile=cover.out -cover ./...
	go tool cover -func=cover.out

The test target does not just run tests. It depends on clean, then critic, then security, then lint, so the static analysis runs before the tests and a failure in any of them stops the chain. The critic target runs gocritic with the enableAll flag, the security target runs gosec, and the lint target runs golangci-lint over the whole module.

The build target then depends on test, and the run target depends on swag and build, which means the API documentation is regenerated before the binary starts. In other words, a developer cannot accidentally ship a build that skipped the checks, because the dependency chain will not let them.

The Go tools the same checks need are the ones the quick start tells you to install: golang-migrate for applying migrations, swaggo/swag for auto-generating the Swagger API docs, securego/gosec for checking Go security issues, go-critic for checking best practice issues, and golangci-lint for the linter checks. Four of the five are in the quality chain, and the fifth is the migration tool.

The cost of this arrangement is a slower loop than running tests alone, and a heavier set of tools to keep current. The benefit is that the checks actually happen.

Migrations, Swagger and the docs folder

Two generated or applied artifacts are part of the workflow: database migrations and API documentation.

The Makefile carries the migration targets, and they point at the platform/migrations folder with a database URL that matches the development Postgres container.

bash
migrate.up:
	migrate -path $(MIGRATIONS_FOLDER) -database "$(DATABASE_URL)" up

migrate.down:
	migrate -path $(MIGRATIONS_FOLDER) -database "$(DATABASE_URL)" down

There is also a migrate.force target that takes a version argument, for the case where a migration has to be marked as applied without running, which is the usual reason people reach for it.

The API documentation is generated with swag, and the resulting Swagger UI is served by the application itself. The quick start points you at the docs page on port 5000, which is the same port the server listens on, so the running service serves its own documentation.

The dependencies behind this are visible in the module file: the swaggo/swag library for the generation side, the gofiber/swagger middleware to serve the UI from a Fiber application, and the go-openapi packages that the generated specification depends on.

The docs folder holds the configuration for that generation, and it is a separate top level directory precisely because the generated documentation is a build artifact of the code, not something to hand edit. The same split applies to migrations, which live under platform because they are about the database, not about the business.

Go 1.24 in go.mod, a 1.23 builder image, and tags from 2022

There are three version markers in this project and they do not agree, which is worth knowing before you build.

The module file declares go 1.24.0 with a toolchain directive of go1.24.1, and the dependency versions are current, with Fiber v2 at 2.52.9, the validator at 10.30.1, the JWT libraries at 5.3.1 and 1.1.2, go-redis v9 at 9.14.0, pgx v4 at 4.18.3, sqlx at 1.4.0, godotenv at 1.5.1 and swag at 1.16.6. The Dockerfile builder, however, uses a golang 1.23 Alpine image. A module that requires 1.24 will not build in a 1.23 toolchain without the toolchain directive downloading a newer one, and the README badge still advertises Go 1.19 or later.

The release history is older than the code. The tags are v1.14.0 from 2022-06-01, v1.13.2 from 2022-02-14 and v1.13.1 from 2022-01-21, so the published versions stopped four years ago, while the last push was on 2026-04-30 and the repository is not archived. In practice you are tracking the master branch and not a release.

The licence is Apache 2.0, credited to Vic Shóstak and True web artisans, which is a permissive grant with an explicit patent clause and no copyleft obligation on your own code.

The practical reading is that this is a template maintained as a moving branch rather than as a versioned product, and that a fresh clone is more current than the last tag.

Editorial conclusion

Adopt fiber-go-template if you want a Go API that starts with sensible answers for the boring decisions, namely folder layout, environment configuration, database and cache wiring, migrations, JWT and generated API docs, and you plan to own the code afterwards. Do not adopt it if you want a framework with an upgrade path, since the tagged releases stop at v1.14.0 from 2022-06-01 and the template ships placeholder secrets such as JWT_SECRET_KEY="secret" that you must change. Before you build on it, copy.env.example to.env and replace the secrets, check that the builder image matches the Go version in go.mod, and run `make docker.run` once to confirm the Postgres, Redis and API containers come up on port 5000.

Frequently asked questions

How do I create a project from the Fiber Go template?

Run `cgapp create` and choose fiber when the CLI asks for a backend framework, then rename .env.example to .env and fill in your environment values. The project can also be used directly as the GitHub module github.com/create-go-app/fiber-go-template.

What does `make docker.run` start?

It creates a dev-network bridge network if needed, starts a postgres container named cgapp-postgres and a redis container, regenerates the Swagger docs, builds and runs the API as cgapp-fiber on port 5000, and applies the pending migrations.

What is the difference between the app, pkg and platform folders?

The app folder holds business logic only and does not care which database driver or cache you use. The pkg folder holds project-specific code such as configuration, middleware, routes and utilities. The platform folder holds platform level logic: the database setup, the cache setup and the migration files.

Which environment variables must I change before deploying?

The JWT_SECRET_KEY and JWT_REFRESH_KEY values in .env.example are the literal placeholders secret and refresh, and STAGE_STATUS is set to dev, which starts the server without a graceful shutdown. The server listens on SERVER_PORT 5000 and the database block defaults to the local cgapp-postgres container.

What licence is the Fiber Go template under?

It is released under the Apache 2.0 licence, credited to Vic Shóstak and True web artisans. The tagged releases stop at v1.14.0 from 2022-06-01, while the last push was on 2026-04-30.

Official sources

  1. create-go-app/fiber-go-template on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/create-go-app-fiber-go-template.svg)](https://hysenlabs.com/projects/create-go-app-fiber-go-template)

Was this useful?