The internal directory gives Go projects an import boundary enforced by the toolchain.

internal packages Model internal imports explicitly so package boundaries stay visible.

Internal Boundaries

importPath
internal_boundaries.go
Replay: real traced execution (multi-file project)
package main

import (
	"fmt"
	"strings"
)

func main() {
	var importPath = "example.com/shop/internal/config"
	ownedPrefix := "example.com/shop/"
	usesInternal := strings.Contains(importPath, "/internal/")
	owned := strings.HasPrefix(importPath, ownedPrefix)
	allowed := !usesInternal || owned

	fmt.Println("import=", importPath)
	fmt.Println("uses_internal=", usesInternal)
	fmt.Println("owned_prefix=", owned)
	fmt.Println("allowed=", allowed)
}
package main

import (
	"fmt"
	"strings"
)

func main() {
	var importPath = "example.com/shop/pkg/config"
	ownedPrefix := "example.com/shop/"
	usesInternal := strings.Contains(importPath, "/internal/")
	owned := strings.HasPrefix(importPath, ownedPrefix)
	allowed := !usesInternal || owned

	fmt.Println("import=", importPath)
	fmt.Println("uses_internal=", usesInternal)
	fmt.Println("owned_prefix=", owned)
	fmt.Println("allowed=", allowed)
}
package main

import (
	"fmt"
	"strings"
)

func main() {
	var importPath = "example.com/other/internal/config"
	ownedPrefix := "example.com/shop/"
	usesInternal := strings.Contains(importPath, "/internal/")
	owned := strings.HasPrefix(importPath, ownedPrefix)
	allowed := !usesInternal || owned

	fmt.Println("import=", importPath)
	fmt.Println("uses_internal=", usesInternal)
	fmt.Println("owned_prefix=", owned)
	fmt.Println("allowed=", allowed)
}
  1. importPath ← "example.com/shop/internal/config", ownedPrefix ← "example.com/shop/"

    8func main() {9  var importPath→ "example.com/shop/internal/config" = "example.com/shop/internal/config" //@importPath="example.com/shop/pkg/config", "example.com/other/internal/config"10  ownedPrefix→ "example.com/shop/" := "example.com/shop/"11  usesInternal→ true := strings.Contains(importPath"example.com/shop/internal/config", "/internal/")12  owned→ true := strings.HasPrefix(importPath"example.com/shop/internal/config", ownedPrefix"example.com/shop/")13  allowed→ true := !usesInternaltrue || ownedtrue1415  fmt.Println("import=", importPath"example.com/shop/internal/config")16  fmt.Println("uses_internal=", usesInternaltrue)17  fmt.Println("owned_prefix=", ownedtrue)18  fmt.Println("allowed=", allowedtrue)19}
    outputimport= example.com/shop/internal/config
    uses_internal= true
    owned_prefix= true
    allowed= true
  1. importPath ← "example.com/shop/pkg/config", ownedPrefix ← "example.com/shop/"

    8func main() {9  var importPath→ "example.com/shop/pkg/config" = "example.com/shop/pkg/config"10  ownedPrefix→ "example.com/shop/" := "example.com/shop/"11  usesInternal→ false := strings.Contains(importPath"example.com/shop/pkg/config", "/internal/")12  owned→ true := strings.HasPrefix(importPath"example.com/shop/pkg/config", ownedPrefix"example.com/shop/")13  allowed→ true := !usesInternalfalse || ownedtrue1415  fmt.Println("import=", importPath"example.com/shop/pkg/config")16  fmt.Println("uses_internal=", usesInternalfalse)17  fmt.Println("owned_prefix=", ownedtrue)18  fmt.Println("allowed=", allowedtrue)19}
    outputimport= example.com/shop/pkg/config
    uses_internal= false
    owned_prefix= true
    allowed= true
  1. importPath ← "example.com/other/internal/config", ownedPrefix ← "example.com/shop/"

    8func main() {9  var importPath→ "example.com/other/internal/config" = "example.com/other/internal/config"10  ownedPrefix→ "example.com/shop/" := "example.com/shop/"11  usesInternal→ true := strings.Contains(importPath"example.com/other/internal/config", "/internal/")12  owned→ false := strings.HasPrefix(importPath"example.com/other/internal/config", ownedPrefix"example.com/shop/")13  allowed→ false := !usesInternaltrue || ownedfalse1415  fmt.Println("import=", importPath"example.com/other/internal/config")16  fmt.Println("uses_internal=", usesInternaltrue)17  fmt.Println("owned_prefix=", ownedfalse)18  fmt.Println("allowed=", allowedfalse)19}
    outputimport= example.com/other/internal/config
    uses_internal= true
    owned_prefix= false
    allowed= false