Nim Lessons Learned

Curated from nim-dojo project experience. Covers common pitfalls, proven patterns, and build configuration.

Thread Safety: {.gcsafe.} Patterns

Handler procs accessing global state (like a connection pool) must wrap access in {.gcsafe.}: blocks. Web frameworks like Mummy run handlers on worker threads.

proc myHandler(request: Request) =
  {.gcsafe.}:
    let pool = getPool()
  # use pool outside the block
  pool.withDb(db):
    # ...

Global Singleton Getter/Setter Pattern

Use a getter/setter pattern for shared singletons instead of exporting a var directly. Avoids circular import issues and keeps initialization explicit.

# pool.nim
var gPool: DbPool

proc setPool*(p: DbPool) =
  gPool = p

proc getPool*(): DbPool =
  gPool

Call setPool() at startup, getPool() in handlers.

db_connector Migration (Nim 2.2+)

In Nim 2.2+, database modules (db_sqlite, db_postgres, etc.) moved to the db_connector package.

# Old (Nim < 2.2):
import std/db_sqlite

# New (Nim 2.2+):
import db_connector/db_sqlite

Install with: nimble install db_connector Add to .nimble: requires "db_connector >= 0.1.0"

MonoTime Import Location

MonoTime and getMonoTime live in std/monotimes, not std/times.

import std/monotimes  # MonoTime, getMonoTime
import std/times      # DateTime, Time, Duration, now()

%* JSON Macro Requires import std/json

The %* JSON construction macro requires import std/json. Even if a module only uses %* in catch blocks or error responses, it needs the import.

import std/json

let body = %* {"error": "not found", "status": 404}

SQLite WAL Sidecar Files

SQLite WAL mode creates *.db-shm and *.db-wal files alongside the database. Add all three patterns to .gitignore:

*.db
*.db-shm
*.db-wal

Build Commands

# Development (compile and run)
nim c -r src/main.nim

# Release (optimized)
nim c -d:danger --opt:speed --panics:on src/main.nim

# With native CPU optimizations and LTO
nim c -d:danger --opt:speed --panics:on --passC:"-march=native -flto" --passL:"-flto" src/main.nim

# Run tests
nimble test

Nim Compiler Config (nim.cfg)

Project-level nim.cfg at repository root. Settings apply to all nim c invocations in the project.

--mm:orc          # Use ORC memory management (recommended for Nim 2.x)
--threads:on      # Enable multi-threading
--outdir:"bin"    # Place compiled binaries in bin/
--path:"src"      # Add src/ to module search path

Nimble Package Manifest (.nimble)

# Package metadata
version       = "0.1.0"
author        = "yourname"
description   = "Project description"
license       = "MIT"
srcDir        = "src"
bin           = @["main_module"]

# Dependencies
requires "nim >= 2.2.0"
requires "mummy >= 0.4.0"
requires "db_connector >= 0.1.0"

# Custom tasks
task dev, "Build and run (development)":
  exec "nim c -r src/main_module.nim"

task release, "Build optimized binary":
  exec "nim c -d:danger --opt:speed --panics:on src/main_module.nim"

task test, "Run tests":
  exec "nim c -r tests/test_something.nim"