glinter

A linter for the Gleam programming language. It parses Gleam source files into ASTs using glance and checks them against a configurable set of rules. Many rules are based on the official Gleam conventions.

Installation

gleam add --dev glinter

Usage

# Lint the src/ directory (default)
gleam run -m glinter

# Lint specific files or directories
gleam run -m glinter src/myapp/ test/

# JSON output
gleam run -m glinter --format json

# Show stats (files, lines, timing)
gleam run -m glinter --stats

# Lint a different project (resolves gleam.toml and paths relative to project dir)
gleam run -m glinter --project /path/to/my/project

The exit code is 1 if any issues are found, 0 otherwise.

Multi-Package Projects

For monorepos with multiple Gleam packages, add glinter as a dev dependency to one package (e.g. server) and lint each package separately using --project:

# From any directory, lint each package
gleam run -m glinter --project server
gleam run -m glinter --project client
gleam run -m glinter --project shared

Each package uses its own gleam.toml for configuration. You can wrap this in a script to lint all packages at once:

#!/bin/sh
# bin/lint
set -e
for pkg in server client shared; do
  echo "Linting $pkg..."
  gleam run -m glinter --project "$pkg"
done

Rules

Error Handling

These rules enforce explicit error handling. Gleam’s Result type exists so errors are handled at every level, not silently discarded.

Code Quality

These rules catch debug artifacts and patterns that shouldn’t ship to production.

Style

These rules enforce consistency and catch patterns that make code harder to read.

Type Annotations

Complexity

Labels

Imports

Cross-Module

FFI

Configuration

Configuration lives in your project’s gleam.toml under the [tools.glinter] key:

[tools.glinter]
stats = true  # show file count, line count, and timing after each run
include = ["src/", "test/"]  # directories to lint (default: ["src/"])
exclude = ["src/server/sql.gleam"]  # skip generated files entirely

[tools.glinter.rules]
avoid_panic = "error"
avoid_todo = "error"
echo = "warning"
assert_ok_pattern = "warning"
discarded_result = "warning"
short_variable_name = "warning"
unnecessary_variable = "warning"
redundant_case = "warning"
unwrap_used = "warning"
deep_nesting = "warning"
function_complexity = "off"  # off by default
module_complexity = "off"  # off by default
prefer_guard_clause = "warning"
missing_labels = "warning"
label_possible = "warning"
unused_exports = "warning"
missing_type_annotation = "warning"
todo_without_message = "warning"
unqualified_import = "warning"
panic_without_message = "warning"
string_inspect = "warning"
duplicate_import = "warning"
unnecessary_string_concatenation = "warning"
trailing_underscore = "warning"
error_context_lost = "warning"
stringly_typed_error = "warning"
thrown_away_error = "warning"
ffi_usage = "off"  # off by default

Each rule can be set to "error", "warning", or "off".

Excluding Files

Skip files entirely (useful for generated code). Supports globs:

[tools.glinter]
exclude = ["src/server/sql.gleam", "src/generated/**/*.gleam"]

Ignoring Rules Per File

Suppress specific rules for files where they don’t make sense. Also supports globs:

[tools.glinter.ignore]
"src/my_complex_module.gleam" = ["deep_nesting", "function_complexity"]
"test/**/*.gleam" = ["assert_ok_pattern", "short_variable_name", "missing_type_annotation", "label_possible", "missing_labels", "unqualified_import"]

Output Formats

Text (default)

src/app.gleam:12: [error] avoid_panic: Use of 'panic' is discouraged
src/app.gleam:25: [warning] echo: Use of 'echo' is discouraged

JSON

gleam run -m glinter --format json
{
  "results": [
    {
      "rule": "avoid_panic",
      "severity": "error",
      "file": "src/app.gleam",
      "line": 12,
      "message": "Use of 'panic' is discouraged"
    }
  ],
  "summary": {
    "total": 1,
    "errors": 1,
    "warnings": 0
  }
}

When --stats is enabled, a stats object is included:

{
  "stats": {
    "files": 23,
    "lines": 2544,
    "elapsed_ms": 45
  }
}

Custom Rules (Plugins)

Add project-specific rules by calling glinter.run with extra rules from your own packages:

// test/review.gleam
import glinter
import my_project/rules

pub fn main() {
  glinter.run(extra_rules: [
    rules.no_raw_sql(),
    rules.require_org_id_filter(),
  ])
}
gleam run -m review

Custom rules use the same builder API as built-in rules and get the same config treatment (on/off/severity in gleam.toml, file-level ignores). See src/glinter/rule.gleam for the API.

If you write a rule that would be useful to the broader Gleam community, PRs are welcome. Contributed rules can ship with a default severity of off so projects opt in explicitly.

Running Tests

gleam test

License

MIT

Search Document