A Go linter that enforces blank lines after block statements to improve code readability.
newline-after-block is a static analysis tool that checks for the presence of blank lines after block statements in Go code.
This helps maintain consistent code formatting and improves readability by visually separating logical blocks of code.
- Detects missing newlines after block statements (
if,for,switch,select, etc.) - Automatic fix support - can automatically insert missing blank lines (
-fixflag) - Ignores composite literals (struct, array, slice, and map literals)
- Skips checks for blocks at the end of functions
- Respects
elseandelse ifclauses - Provides clear, actionable error messages with file and line number references
go install github.com/breml/newline-after-block/cmd/newline-after-block@latestgit clone https://github.com/breml/newline-after-block.git
cd newline-after-block
go build -o bin/newline-after-block ./cmd/newline-after-blockor if task is installed:
task buildRun the linter on your Go packages:
newline-after-block ./...Run on specific files or directories:
newline-after-block ./pkg/mypackage
newline-after-block ./cmd/myapp/main.goFor integration with golangci-lint, follow the instructions in
Module Plugin System and add the following to your .golangci.yml:
linters:
enable:
- newline-after-block
custom:
newline-after-block:
path: /path/to/newline-after-block
description: Checks for newline after block statements
original-url: https://github.com/breml/newline-after-blockThe linter enforces a blank line after these block statements:
ifstatements (when not followed byelse)forloopsrangeloopsswitchstatementstype switchstatementsselectstatements
The linter does not enforce newlines in these cases:
- Blocks at the end of functions
ifstatements followed byelseorelse if- Blocks followed by closing braces (e.g., end of another block)
- Composite literals (struct, array, slice, map literals)
func example() {
if condition {
doSomething()
} // missing blank line after if block
nextStatement()
}
func loop() {
for i := 0; i < 10; i++ {
process(i)
} // missing blank line after for block
fmt.Println("done")
}func example() {
if condition {
doSomething()
}
nextStatement() // Blank line present
}
func loop() {
for i := 0; i < 10; i++ {
process(i)
}
fmt.Println("done") // Blank line present
}
func endOfFunction() {
if condition {
doSomething()
}
// No blank line needed - end of function
}
func elseClause() {
if condition {
doSomething()
} else {
doSomethingElse()
}
// No blank line needed after else
}
func structLiteral() {
p := Person{
Name: "John",
Age: 30,
}
fmt.Println(p) // No blank line needed - composite literal
}- Go 1.25 or later
- Task (optional, for running tasks)
- golangci-lint (for linting)
task build # Build the linter binary
task test # Run all tests
task test-verbose # Run tests with verbose output
task test-coverage # Run tests with coverage report
task lint # Run golangci-lint
task lint-fix # Run golangci-lint with auto-fix
task run # Run the linter on the project itself
task clean # Clean build artifacts
task verify # Run all verification tasks (build, test, lint)# Run all tests
go test -v ./...
# Or using task
task testContributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass:
task verify - Submit a pull request
This linter was created to replace a shell script that used sed and grep to check for newlines after closing braces.
The shell script had limitations:
- Could not distinguish between block statements and composite literals
- Did not handle ending of nested blocks correctly
The new Go-based linter uses the Go AST (Abstract Syntax Tree) to accurately identify block statements and apply the rules correctly.
Copyright 2025 by Lucas Bremgartner (breml)