A production-ready Go web API starter template with proper configuration, testing, and development tooling. Deploy to Fly.io with ease.
- ✅ Modern Go project structure
- ✅ Chi router with middleware
- ✅ Prometheus metrics
- ✅ Comprehensive test suite (unit, integration, acceptance)
- ✅ Docker support
- ✅ Fly.io deployment configuration
- ✅ Git hooks for code quality
- ✅ VSCode integration
- ✅ Strict linting with performance focus
- ✅ Retro pixel art landing page demo
- ✅ GitHub Actions CI/CD workflows
- Go 1.21 or later
- golangci-lint (for code linting)
- Git
- Visual Studio Code (recommended IDE)
# Clone the repository
git clone https://github.com/umuterturk/go-web-base-fly-io.git
cd go-web-base-fly-io
# Install dependencies
go mod download
# Run the server
go run cmd/api/main.go
# Access the retro landing page
open http://localhost:8080
Linux
# Ubuntu/Debian
wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
# Add to ~/.bashrc or ~/.zshrc
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc
# Verify installation
go version
macOS
# Using Homebrew
brew install go
# Or manual installation
wget https://go.dev/dl/go1.21.6.darwin-amd64.pkg
open go1.21.6.darwin-amd64.pkg
# Follow the installer instructions
# Add to ~/.zshrc or ~/.bash_profile
echo 'export GOPATH=$HOME/go' >> ~/.zshrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.zshrc
source ~/.zshrc
# Verify installation
go version
Windows
-
Download the installer from golang.org/dl
-
Run the installer and follow the prompts
-
Verify installation by opening Command Prompt or PowerShell:
go version
-
Set up environment variables (if not done by installer):
- Right-click on "This PC" > Properties > Advanced system settings > Environment Variables
- Add/update the following:
- GOPATH:
%USERPROFILE%\go
- Add to PATH:
%USERPROFILE%\go\bin
- GOPATH:
Linux
# Binary installation
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# Using Snap
sudo snap install golangci-lint
# Verify installation
golangci-lint --version
macOS
# Using Homebrew
brew install golangci-lint
# Verify installation
golangci-lint --version
Windows
# Using Scoop
scoop install golangci-lint
# Using Chocolatey
choco install golangci-lint
# Manual installation
# Download from https://github.com/golangci/golangci-lint/releases
# Extract and add to PATH
# Verify installation
golangci-lint --version
These tools enhance your Go development experience:
# Essential Go development tools
go install golang.org/x/tools/gopls@latest # Go language server
go install golang.org/x/tools/cmd/goimports@latest # Import organization
go install github.com/go-delve/delve/cmd/dlv@latest # Debugger
go install github.com/fatih/gomodifytags@latest # JSON/YAML tag management
go install github.com/josharian/impl@latest # Interface implementation generator
go install honnef.co/go/tools/cmd/staticcheck@latest # Static analysis
go install golang.org/x/tools/cmd/godoc@latest # Documentation server
-
Install Visual Studio Code
-
Install the recommended extensions:
-
Open the project in VSCode:
code .
-
When prompted, install the Go tools that VSCode recommends
.
├── .github/ # GitHub configuration
│ └── workflows/ # GitHub Actions workflows
├── cmd/ # Application entry points
│ └── api/ # API server
├── internal/ # Private application code
│ ├── api/ # API-specific code
│ │ ├── handlers/ # HTTP handlers
│ │ ├── middleware/ # HTTP middleware
│ │ └── router.go # Router setup
│ └── config/ # Configuration
├── docs/ # Static assets to serve (naming is off but did so to use in github pages)
│ ├── css/ # CSS stylesheets
│ ├── js/ # JavaScript files
│ ├── img/ # Images and graphics
│ └── index.html # Landing page
├── tests/ # Test suites
│ ├── acceptance/ # End-to-end tests
│ ├── integration/ # Integration tests
│ └── unit/ # Unit tests
├── .golangci.yml # Linter configuration
├── Dockerfile # Container definition
├── fly.toml # Fly.io configuration
├── go.mod # Go module definition
└── README.md # This file
The project includes GitHub Actions workflows for automated CI/CD:
-
Tests Workflow (
.github/workflows/tests.yml
):- Triggers on pushes/PRs to the main branch
- Sets up Go environment
- Installs dependencies
- Runs linter checks with golangci-lint
- Executes all tests with race condition detection
-
Deployment Workflow (
.github/workflows/deploy.yml.base
):- Activates after successful test workflow completion
- Deploys to Fly.io when commit messages contain "deploy to fly.io"
- Requires setting up a
FLY_API_TOKEN
secret in your repository - Rename from
.base
extension and customize as needed
To enable the deployment workflow:
# Rename the base file to activate it
mv .github/workflows/deploy.yml.base .github/workflows/deploy.yml
# Add your Fly.io API token as a repository secret named FLY_API_TOKEN
The project includes Git hooks for code quality:
- pre-commit: Runs linting checks before each commit
- pre-push: Runs all tests before pushing to remote
# Terminal
go run cmd/api/main.go
# VSCode
F5 or Run > Start Debugging (Launch API configuration)
The project includes a retro pixel art style landing page to demonstrate static file serving:
- Visit
http://localhost:8080/
after starting the server - Features interactive elements and API integration
- Includes a theme switcher and Konami code easter egg (↑↑↓↓←→←→BA)
- Demonstrates serving static assets (HTML, CSS, JS, SVG)
This project demonstrates handling static files in a Go web application:
-
File Structure
- All static assets are in the
docs/
directory (naming is off but did so to use in github pages) index.html
serves as the main landing page- CSS, JavaScript, and images are in separate subdirectories
- All static assets are in the
-
Router Configuration (in
internal/api/router.go
)// Serve static files fileServer := http.FileServer(http.Dir("docs")) r.Handle("/*", fileServer) // API routes under /api/v1 prefix r.Route("/api/v1", func(r chi.Router) { r.Get("/health", handlers.HealthHandler) r.Get("/hello", handlers.HelloHandler) })
-
Adding New Pages
- Place HTML files in the
docs/
directory - Add CSS and JavaScript in respective subdirectories
- Reference them with paths relative to the static root (e.g.,
/css/styles.css
)
- Place HTML files in the
-
Best Practices
- Serve static files from root paths
- Keep API endpoints separate under the
/api/v1
prefix
Variable | Description | Default |
---|---|---|
PORT |
Server port | 8080 |
LOG_LEVEL |
Logging level (debug, info, warn, error) | info |
API_BASE_URL |
Base URL for acceptance tests | - |
# Run all tests
go test ./...
# Run specific test suites
go test ./tests/unit # Unit tests
go test ./tests/integration # Integration tests
go test ./tests/acceptance # Acceptance tests (requires API_BASE_URL)
# Run with coverage
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out -o coverage.html
In VSCode:
- Run > Start Debugging > Test Current File
- Run > Start Debugging > Test All
# Run linter
golangci-lint run ./...
# In VSCode
View > Command Palette > Go: Lint Workspace
- Set breakpoints by clicking the gutter or pressing F9
- Start debugging with F5
- Use the Debug toolbar for:
- Continue (F5)
- Step Over (F10)
- Step Into (F11)
- Step Out (Shift+F11)
- Restart (Ctrl+Shift+F5)
- Stop (Shift+F5)
# Build the image
docker build -t go-web-api .
# Run the container
docker run -p 8080:8080 go-web-api
This project is configured for easy deployment to Fly.io, a platform for running full-stack apps globally.
Initial Setup
-
Install the Fly.io CLI:
# macOS / Linux curl -L https://fly.io/install.sh | sh # Windows PowerShell iwr https://fly.io/install.ps1 -useb | iex
-
Add flyctl to your PATH (if the installer didn't do it automatically)
-
Sign up or log in to Fly.io:
# Sign up fly auth signup # Or log in fly auth login
-
Verify your installation:
fly version
Deploying After Forking
If you've forked this repository, you'll need to update the app name in fly.toml
:
-
Open
fly.toml
and update the app name:app = "your-app-name" # Change this to a unique name
-
Launch the app for the first time:
fly launch
- When prompted, select "No" to creating a new app
- Select "Yes" to use an existing configuration
- Choose your preferred region
- Select "No" to setting up a PostgreSQL database
- Select "No" to setting up a Redis database
- Select "Yes" to deploy now
-
For subsequent deployments:
fly deploy
-
View your deployed app:
fly open
-
Check app status:
fly status
-
View logs:
fly logs
To use the GitHub Actions deployment workflow:
-
Generate a Fly.io API token:
fly auth token
-
Add the token as a secret in your GitHub repository:
- Go to Settings > Secrets and variables > Actions > New repository secret
- Name:
FLY_API_TOKEN
- Value: Your Fly.io API token
-
Rename the deployment workflow file:
mv .github/workflows/deploy.yml.base .github/workflows/deploy.yml
-
When ready to deploy, include "deploy to fly.io" in your commit message:
git commit -m "Updated application features - deploy to fly.io"
-
Push to main branch, and the workflow will automatically deploy
Environment Variables
Set environment variables for your Fly.io deployment:
# Set a single environment variable
fly secrets set PORT=8080
# Set multiple environment variables
fly secrets set PORT=8080 LOG_LEVEL=info
# View current secrets
fly secrets list
Scaling
Scale your application on Fly.io:
# Scale to multiple instances
fly scale count 2
# Scale machine size
fly scale vm shared-cpu-1x
# View current scale
fly status
Monitoring
Monitor your application:
# View logs
fly logs
# View metrics dashboard
fly dashboard
# SSH into the VM
fly ssh console
Troubleshooting
Common issues and solutions:
-
Deployment fails with "App name already exists":
- Change the app name in
fly.toml
- Or create a new app with
fly apps create your-app-name
- Change the app name in
-
Port binding issues:
- Ensure your app is listening on the port specified by the
PORT
environment variable - The default port in this template is 8080
- Ensure your app is listening on the port specified by the
-
Resource constraints:
- Scale up your VM with
fly scale vm shared-cpu-2x
- Or add more memory with
fly scale memory 1024
- Scale up your VM with
-
Networking issues:
- Check your firewall settings with
fly status
- Ensure your app is properly handling HTTP requests
- Check your firewall settings with
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
If you find this project helpful and would like to support its development:
- ☕ Buy me a coffee
- 🐦 Follow me on X/Twitter for updates
- ⭐ Star the repository on GitHub
- 🐛 Report bugs or suggest features through GitHub issues
This project is licensed under the MIT License - see the LICENSE file for details.