Question

Go Filename Conventions: Naming Source Files and Structs

gonaming-conventions

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 web or store.
  • 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.

Take Quiz

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:

  1. The Go tool finds the web directory.
  2. It collects the Go files that apply to the current operating system and build settings.
  3. It compiles server.go and routes.go together as package web.
  4. routes.go can use Server directly because it is in the same package.
  5. Code in another package can use exported names, such as web.Server and HomeRoute.

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, and handlers.go.
  • Database access: store.go, users.go, migrations.go, and queries.go.
  • Configuration: config.go, config_file.go, and config_env.go.
  • Authentication: token.go, password.go, and middleware.go.
  • Command-line tools: main.go, commands.go, flags.go, and output.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.

Take Quiz

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, or store.go.
  • Put methods in separate files when the type grows, grouped by behavior such as client_auth.go or client_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.go is often more useful than http_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

TopicGo convention or behaviorJava-style expectation
Source file and type nameNo required matchOften one public class per matching file
Types per fileAny practical numberOften one main class per file
Package compilationAll applicable .go files in a directory compile as one packageClasses are generally separate compilation units
Filename casingUsually lowercase; underscores are validOften matches PascalCase class name
Import targetPackage pathPackage/class usage differs by tooling
Filename formWhen it works well
server.goThe package already explains what kind of server it is.
web_server.goThe package contains multiple kinds of servers or the extra word prevents ambiguity.
server_http.goThe file specifically contains HTTP-related server behavior.
server_test.goTests for server behavior; recognized specially by go test.
Take Quiz

Cheat Sheet

  • A Go package may contain multiple .go files.
  • 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 web often uses server.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 .go files.
  • Important suffixes include:
    • _test.go for 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.

Take Quiz

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

  1. Create a package named web.
  2. Define a Server struct with a Name field in server.go.
  3. Add a constructor that returns a Server value.
  4. Add a HomePath method in routes.go.
  5. Add a test in server_test.go that verifies the generated path.
Take Quiz

Keep learning

Related questions

View more