Question
Are there naming conventions for Go source filenames similar to Go package naming conventions, such as lowercase names without underscores?
Should a Go project place one struct in each file and name that file after the struct, as is often done for Java classes?
For example, if a project defines a WebServer struct, is web_server.go an appropriate filename?
Short Answer
Go does not require a one-type-per-file layout, and it has no compiler-enforced general filename style beyond the .go extension and a few special suffixes. Organize files around related responsibilities. A name such as web_server.go is valid and understandable, although Go projects often prefer short, lowercase names such as server.go when the package already provides the context.
Concept
A Go package can contain many .go files. When Go builds the package, it treats the applicable files in that directory as one unit. Types, functions, constants, and variables can be declared in any of those files and used by other files in the same package.
Unlike Java, Go does not require:
- one struct or type per file;
- a filename matching a type name;
- a public type to live in a specially named file.
For ordinary source files, Go style is largely a matter of local project consistency. Use lowercase names and make the filename describe the responsibility of the code inside it. Underscores are valid and are commonly useful for multiword filenames.
For example, these are all valid Go files:
server.go
web_server.go
http_handler.go
config.go
user_store.go
In a package named web, server.go is usually clearer than web_server.go, because callers already see the package context:
web.NewServer()
A filename should help a developer find code. It is not part of the package's public API and normally does not affect how code imports or uses the package.
Mental Model
Think of a Go package as a folder containing pages of one notebook.
- The package is the notebook's subject, such as
weborstore. - Each file is a page grouped by a topic, such as servers, handlers, or configuration.
- A struct is one note on a page.
You do not need one page for every note. Put closely related notes together, and start a new page when the current one becomes hard to navigate.
Syntax and Examples
Every ordinary Go source file begins with a package declaration. Files in the same directory can belong to the same package.
// server.go
package web
type Server struct {
Address string
}
func NewServer(address string) *Server {
return &Server{Address: address}
}
// handler.go
package web
func (s *Server) HealthStatus() string {
return "ok"
}
Even though Server is declared in server.go, its HealthStatus method can be declared in handler.go because both files are in package web.
For a multiword type, use Go naming conventions for the identifier:
type WebServer struct {
Port int
}
A related filename can be either of these:
server.go // Often best if the package context makes "web" redundant.
web_server.go // Valid and useful when it distinguishes this from another server.
The filename does not need to exactly match WebServer.
Step by Step Execution
Consider this directory:
web/
├── server.go
└── routes.go
server.go:
package web
type Server struct {
Name string
}
routes.go:
package web
func (s Server) HomeRoute() string {
return "/" + s.Name
}
When another package imports web, this happens:
- The Go tool finds the
webdirectory. - It collects the Go files that apply to the current operating system and build settings.
- It compiles
server.goandroutes.gotogether as packageweb. routes.gocan useServerdirectly because it is in the same package.- Code in another package can use exported names, such as
web.ServerandHomeRoute.
The order of normal .go files does not determine whether one file can refer to declarations in another file.
Real World Use Cases
Filename grouping is useful when a package has several related responsibilities.
- HTTP application:
server.go,routes.go,middleware.go, andhandlers.go. - Database access:
store.go,users.go,migrations.go, andqueries.go. - Configuration:
config.go,config_file.go, andconfig_env.go. - Authentication:
token.go,password.go, andmiddleware.go. - Command-line tools:
main.go,commands.go,flags.go, andoutput.go.
The goal is quick navigation: a developer looking for route registration should reasonably expect it in routes.go, not need to know the name of every type first.
Real Codebase Usage
In real Go codebases, files are usually split by cohesion: code that changes together and serves the same purpose is kept together.
Common patterns include:
- Put a central type and its primary constructor in
server.go,client.go, orstore.go. - Put methods in separate files when the type grows, grouped by behavior such as
client_auth.goorclient_requests.go. - Keep interfaces near the code that consumes them when that makes dependencies clearer.
- Keep tests in files ending in
_test.go, usually beside the code they test. - Use names that avoid repeating the package name. In package
httpclient,client.gois often more useful thanhttp_client.go.
Start simple. A small package can reasonably use one or two files. Split files when they become long, mix unrelated concerns, or become difficult to scan. Do not create a new file merely because a new struct was added.
Common Mistakes
Assuming Java's one-class-per-file rule applies
This is unnecessary in Go:
user.go
user_service.go
user_repository.go
user_validator.go
It may be appropriate in a large package, but only if those files represent meaningful responsibilities. A tiny package may be clearer with related types together.
Trying to use a filename as an import name
Imports refer to packages, not source filenames:
import "example.com/project/web"
You cannot import server.go directly.
Repeating package context everywhere
In a web package, this can be redundant:
web_server.go
web_routes.go
web_middleware.go
Prefer shorter names when there is no ambiguity:
server.go
routes.go
middleware.go
Forgetting special Go filename suffixes
Some suffixes have meanings to the Go tool. For example, server_test.go is a test file, while server.go is normal source. Do not rename a normal production file to end in _test.go unless it contains tests.
Using inconsistent naming without a reason
Both web_server.go and webserver.go can be valid, but a project should choose a readable convention and apply it consistently. Go projects commonly use lowercase words separated by underscores when multiple words need separation.
Comparisons
| Topic | Go convention or behavior | Java-style expectation |
|---|---|---|
| Source file and type name | No required match | Often one public class per matching file |
| Types per file | Any practical number | Often one main class per file |
| Package compilation | All applicable .go files in a directory compile as one package | Classes are generally separate compilation units |
| Filename casing | Usually lowercase; underscores are valid | Often matches PascalCase class name |
| Import target | Package path | Package/class usage differs by tooling |
| Filename form | When it works well |
|---|---|
server.go | The package already explains what kind of server it is. |
web_server.go | The package contains multiple kinds of servers or the extra word prevents ambiguity. |
server_http.go | The file specifically contains HTTP-related server behavior. |
server_test.go | Tests for server behavior; recognized specially by go test. |
Cheat Sheet
- A Go package may contain multiple
.gofiles. - Go does not require one struct per file.
- Go does not require a file to have the same name as a struct.
- Use lowercase, descriptive filenames.
- Underscores in filenames are valid and commonly used for multiple words:
web_server.go. - Avoid redundant words already supplied by the package name: package
weboften usesserver.go. - Organize files by responsibility, not strictly by type.
- Files in the same package can use each other's declarations.
- Imports target package paths, never individual
.gofiles. - Important suffixes include:
_test.gofor tests_linux.go,_windows.go, and similar OS-specific files_amd64.go,_arm64.go, and similar architecture-specific files
For the original example, web_server.go is valid. In a package dedicated to web servers, server.go is often the more idiomatic concise choice.
FAQ
Should Go filenames use underscores?
Yes. Go has no general rule forbidding underscores in filenames. web_server.go is valid and readable.
Should every Go struct be in its own file?
No. Keep related types together. Split files when doing so improves navigation and separation of responsibilities.
Must a Go filename match the struct name?
No. A WebServer type can be declared in server.go, web_server.go, or another relevant file.
Is web_server.go a good name for a WebServer struct?
Yes. It is clear. If the package is already named web, server.go may be shorter and avoid repetition.
Can methods for one Go type be in different files?
Yes. Any file in the same package can declare methods for a type declared elsewhere in that package.
Does the order of Go files matter?
No. Ordinary files in the same package are compiled together; declaration visibility is package-wide.
Which Go filenames have special meaning?
Files ending in _test.go are test files. OS and architecture suffixes, such as _linux.go and _arm64.go, can also control which files are included in a build.
Mini Project
Description
Create a small web package that demonstrates how one Go type can be declared in one file while its related behavior lives in another file. This mirrors a practical package layout without forcing one type per file.
Goal
Build and test a package where a Server type is defined in server.go and route-related methods are defined in routes.go.
Requirements
- Create a package named
web. - Define a
Serverstruct with aNamefield inserver.go. - Add a constructor that returns a
Servervalue. - Add a
HomePathmethod inroutes.go. - Add a test in
server_test.gothat verifies the generated path.
Keep learning
Related questions
Are Go Maps Passed by Value or Reference?
Learn Go map parameter and return semantics: maps are passed by value, while copies share underlying data. Know when map pointers are useful.
Authentication for Go REST APIs: Sessions, Tokens, and Middleware
Learn practical authentication patterns for Go REST APIs, including password hashing, server sessions, bearer tokens, middleware, and security rules.
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.