tezvyn:

What is the purpose of the internal directory in Go?

AI-drafted, machine-checkedSource: go.devintermediate

Tests Go visibility boundaries beyond exported vs unexported. A strong answer states that internal is compiler-enforced module privacy, while lowercase is only package-private. Red flag: calling internal a naming convention rather than a build boundary.

WHAT THIS TESTS: This question tests whether you understand the difference between package-level and module-level access control in Go. Interviewers want to see that you know the compiler enforces visibility boundaries, not just naming conventions, and that you can reason about API stability and refactoring freedom across package boundaries.

A GOOD ANSWER COVERS: First, state that the internal directory is a special path segment recognized by the Go compiler that prevents packages inside it from being imported by code outside the module. Second, contrast this with unexported lowercase identifiers, which restrict visibility to the declaring package only. Third, explain that internal is the right choice when multiple packages within your own module need to share code, but you want to guarantee that external modules cannot depend on it. Fourth, mention the practical benefit: because external users cannot import internal packages, you retain the freedom to refactor their APIs without violating semantic versioning or breaking downstream consumers.

COMMON WRONG ANSWERS: A red flag is saying internal is just a team convention or naming convention without compiler enforcement. Another mistake is claiming that lowercase unexported identifiers achieve the same goal; they only work within a single package, so they cannot help when two sibling packages need to share helpers. Also avoid suggesting that internal hides code from the standard library or the same module; internal packages are fully visible to other packages within the same module.

LIKELY FOLLOW-UPS: The interviewer may ask how internal interacts with semantic versioning and whether moving a public API into internal is a breaking change. They might also ask where to place test helpers or command-line tools that should not be imported, or how internal differs from vendor directories.

ONE CONCRETE EXAMPLE: Imagine a module github.com/example/api with a root package and a complex authentication flow. You split auth logic into an internal/auth package so that cmd/server and the root api package can both import it. Because the path contains internal, a consumer who runs go get github.com/example/api cannot write import github.com/example/api/internal/auth; the build fails. If you later rename a function in internal/auth, you only need to update imports inside your own module, not issue a major version bump.

Read the original → go.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.