RepoPilotOpen in app →

riok/mapperly

A .NET source generator for generating object mappings. No runtime reflection.

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit today
  • 11 active contributors
  • Apache-2.0 licensed
Show 3 more →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 55% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/riok/mapperly)](https://repopilot.app/r/riok/mapperly)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/riok/mapperly on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: riok/mapperly

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/riok/mapperly shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit today
  • 11 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 55% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live riok/mapperly repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/riok/mapperly.

What it runs against: a local clone of riok/mapperly — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in riok/mapperly | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>riok/mapperly</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of riok/mapperly. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/riok/mapperly.git
#   cd mapperly
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of riok/mapperly and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "riok/mapperly(\\.git)?\\b" \\
  && ok "origin remote is riok/mapperly" \\
  || miss "origin remote is not riok/mapperly (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "Riok.Mapperly.slnx" \\
  && ok "Riok.Mapperly.slnx" \\
  || miss "missing critical file: Riok.Mapperly.slnx"
test -f "Directory.Build.props" \\
  && ok "Directory.Build.props" \\
  || miss "missing critical file: Directory.Build.props"
test -f ".github/workflows/test.yml" \\
  && ok ".github/workflows/test.yml" \\
  || miss "missing critical file: .github/workflows/test.yml"
test -f "README.md" \\
  && ok "README.md" \\
  || miss "missing critical file: README.md"
test -f "docs/docs/contributing/architecture.md" \\
  && ok "docs/docs/contributing/architecture.md" \\
  || miss "missing critical file: docs/docs/contributing/architecture.md"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/riok/mapperly"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Mapperly is a .NET source generator that generates compile-time object mapping code (no runtime reflection) for transforming between DTOs, domain models, and other C# types. It produces readable, debuggable C# code at build time rather than using reflection-based mappers like AutoMapper, eliminating runtime overhead and enabling full compile-time safety. Single C# project structured as a Roslyn-based source generator (Riok.Mapperly.slnx). Core logic lives in source generator implementation (parsing mapper declarations, generating code), with separate benchmarks/Riok.Mapperly.Benchmarks/ for performance testing and /docs/ (Docusaurus-based) for documentation. Configuration-driven via .csharpierrc.yaml for code formatting and .editorconfig for IDE settings.

👥Who it's for

.NET developers (C# primary) building applications that need to map between objects (e.g., domain models ↔ DTOs, API contracts ↔ internal models) while maintaining zero runtime reflection overhead and type safety, particularly in performance-critical contexts like high-throughput APIs or real-time systems.

🌱Maturity & risk

Production-ready and actively maintained. The project has published multiple stable releases (v3.0, v4.0, v5.0 with documented breaking changes in /docs/docs/breaking-changes/), comprehensive CI/CD pipelines in .github/workflows/ (test, lint, benchmark, release workflows), and clear versioning strategy spanning stable and next release channels. However, as a source generator, it requires .NET 5+ toolchain support.

Low operational risk for adopters but moderate maintenance complexity. The project is actively maintained by riok but relatively specialized (source generators are non-trivial C# metaprogramming); breaking changes across major versions indicate architectural evolution. Limited information on active maintainer count; dependabot is configured suggesting automated dependency management. Risk is mitigated by semantic versioning and published upgrade guides.

Active areas of work

Active development with documented breaking changes across versions, benchmark suite for performance tracking, and multi-channel release strategy (stable + next preview channel). CI validates PRs via test, lint, and CodeQL workflows. Documentation pipeline includes auto-draft release notes.

🚀Get running

git clone https://github.com/riok/mapperly.git
cd mapperly
dotnet restore
dotnet build
dotnet test

Daily commands:

dotnet build                    # Builds the source generator
dotnet test                     # Runs test suite
dotnet run -p benchmarks/Riok.Mapperly.Benchmarks/  # Runs benchmarks
cd docs && npm run start       # Starts Docusaurus dev server on localhost:3000

🗺️Map of the codebase

  • Riok.Mapperly.slnx — Solution file that defines the entire project structure and dependencies for the source generator
  • Directory.Build.props — Central build configuration for all projects, defines shared properties and SDK versions
  • .github/workflows/test.yml — CI/CD pipeline that validates all contributions; must pass before merging
  • README.md — Project overview and quickstart; every contributor should understand the project's core purpose
  • docs/docs/contributing/architecture.md — Architecture documentation that explains the source generator's design and component interactions
  • CONTRIBUTING.md — Guidelines for contributing, coding standards, and development workflow
  • .config/dotnet-tools.json — Defines required .NET tools (formatters, linters) that all developers must use

🧩Components & responsibilities

  • Source Generator (Roslyn, C# Syntax Trees) — Parses mapper interface definitions, analyzes type hierarchies, generates optimized mapping code
    • Failure mode: Invalid generated code, infinite compilation loops, performance regressions
  • Analyzer/Diagnostics (Roslyn DiagnosticAnalyzer) — Validates mapping configurations, type compatibility, and configuration rules; emits compiler diagnostics
    • Failure mode: Missing error detection, false positives blocking valid mappings, unclear diagnostic messages
  • Test Suite (xUnit or similar) — Unit and integration tests validating generated mapper correctness, edge cases, and feature combinations
    • Failure mode: Undetected regressions, flaky tests, incomplete feature coverage
  • Documentation Site (Docusaurus, TypeScript) — Comprehensive guides for mapper configuration, diagnostics, best practices, and API reference
    • Failure mode: Outdated docs, unclear examples, broken links, poor version navigation
  • Benchmark Suite (BenchmarkDotNet) — Performance tests measuring generated code speed and source generation overhead
    • Failure mode: Silent performance regressions, flaky timing measurements, incomplete coverage

🔀Data flow

  • Developer codeSource Generator — Mapper interface definition with attributes flows to generator during compilation
  • Source GeneratorAnalyzer — Generated code and configuration validated by analyzer for rule violations
  • AnalyzerDeveloper IDE — Diagnostics (RMG error codes) surface as compiler errors/warnings in editor
  • Source GeneratorC# Compiler — Generated mapper classes emitted as source code for compilation
  • C# CompilerApplication Runtime — Compiled mapper assemblies with zero-cost generated mapping methods
  • DocumentationDeveloper — Configuration guides and diagnostic references help developers fix mapping issues

🛠️How to make changes

Add a New Mapping Configuration Feature

  1. Create feature documentation in the configuration docs folder (docs/docs/configuration/[feature-name].mdx)
  2. Add analyzer diagnostic documentation if validation is needed (docs/docs/configuration/analyzer-diagnostics/RMG[NNN].mdx)
  3. Update sidebars to register new documentation page (docs/sidebars.js)

Add a New Analyzer Diagnostic Rule

  1. Create diagnostic documentation with rule code and examples (docs/docs/configuration/analyzer-diagnostics/RMG[NNN].mdx)
  2. Register the diagnostic in the analyzer diagnostics index (docs/docs/configuration/analyzer-diagnostics/index.mdx)
  3. Add test cases in the test project to verify rule behavior

Add a Performance Benchmark

  1. Add benchmark method to the appropriate benchmark class (benchmarks/Riok.Mapperly.Benchmarks/MappingBenchmarks.cs)
  2. Run benchmark suite via the benchmark workflow (.github/workflows/benchmark.yml)

Update Documentation Site

  1. Create or update markdown/MDX files in docs/docs/ folder (docs/docs/[category]/[topic].mdx)
  2. Run prebuild script to validate documentation structure (docs/prebuild.ts)
  3. Update sidebars configuration if creating new top-level section (docs/sidebars.js)

🔧Why these technologies

  • C# Source Generators (.NET) — Enables compile-time code generation with zero runtime reflection overhead, allowing developers to inspect generated mapping code
  • Docusaurus — Modern static documentation site with versioning support, essential for complex API documentation and release notes
  • Roslyn — Microsoft's compiler platform used by source generators to analyze and generate C# code with full semantic understanding
  • BenchmarkDotNet — Gold-standard microbenchmarking framework to rigorously measure mapping performance and ensure no regressions

⚖️Trade-offs already made

  • Compile-time code generation instead of runtime reflection

    • Why: Eliminates runtime performance overhead and enables compile-time validation
    • Consequence: Slower initial build time; errors caught at compile rather than runtime; generated code visible and auditable
  • Extensive documentation over minimal examples

    • Why: Source generators have complex configuration options requiring thorough guidance
    • Consequence: Higher maintenance burden for docs; clearer path for developers learning the framework
  • Separate analyzer for diagnostics rather than runtime validation

    • Why: Provides immediate IDE feedback and prevents invalid mappers from compiling
    • Consequence: Additional complexity in diagnostic system; superior developer experience

🚫Non-goals (don't propose these)

  • Runtime reflection-based mapping (intentionally avoids AutoMapper/Entity Framework style)
  • Cross-language code generation (C# only)
  • Dynamic mapper registration or runtime configuration
  • Support for non-.NET platforms

⚠️Anti-patterns to avoid

  • Potential incomplete test coverage for edge cases (Medium)benchmarks/ and test structure: Source generators have high complexity with many configuration combinations; incomplete test coverage could allow subtle bugs in rare scenarios
  • Documentation drift risk (Medium)docs/docs/configuration/: Complex API with many configuration options increases likelihood of documentation falling out of sync with implementation

🔥Performance hotspots

  • Source generation phase (Compile-time performance) — Roslyn-based code generation must parse and analyze entire type hierarchies; complex nested mappings could significantly slow compilation
  • Analyzer diagnostic validation (IDE responsiveness) — Comprehensive diagnostic system checking many rules for each mapping configuration could impact IDE responsiveness on large projects
  • Documentation site build (undefined) — Docusaurus with

🪤Traps & gotchas

Node.js version requirement: docs subfolder requires Node >=24.12.0 (see docs/package.json engines field); running npm commands in wrong directory fails silently. Docusaurus prebuild step: docs require ts-node prebuild.ts before serving (see prestart script in docs/package.json). Source generator versioning: targets specific Roslyn APIs tied to .NET SDK version; may fail silently if wrong .NET SDK is installed. Breaking changes across majors: v3→v4→v5 have documented breaking changes; existing mapper code may not compile without updates.

🏗️Architecture

💡Concepts to learn

  • Roslyn Source Generators — Mapperly is a source generator; understanding how Roslyn analyzes C# syntax trees, emits code at compile-time, and integrates with the build pipeline is fundamental to modifying or extending Mapperly
  • Syntax Tree Visitation Pattern — Mapperly uses visitor patterns to traverse Roslyn syntax trees and identify mapper declarations; understanding this pattern is essential for adding new mapper features or analyzing type hierarchies
  • Compile-Time Code Generation — Unlike reflection-based mappers, Mapperly generates readable C# code at build time; understanding this trade-off (type safety, performance, debuggability vs. runtime flexibility) is core to Mapperly's design philosophy
  • Semantic Versioning with Breaking Changes — Mapperly documents breaking changes explicitly (v3.0, v4.0, v5.0); contributors must understand semver discipline and upgrade paths when modifying the public API
  • Attribute-Driven Code Generation — Mapperly uses [Mapper] attributes to declare intent; the source generator parses these annotations and synthesizes implementations, making attribute design critical for API ergonomics
  • Diagnostic Reporting in Roslyn — Source generators emit diagnostics (errors, warnings) during compilation; Mapperly likely uses DiagnosticDescriptor to report unmappable types or configuration issues
  • AutoMapper/AutoMapper — Reflection-based object mapper; direct predecessor/competitor solving the same DTO mapping problem but with runtime overhead
  • MapsterMapper/Mapster — Expression-tree based mapper; alternative approach to zero-reflection mapping in .NET with compile-time code generation
  • dotnet/roslyn — Roslyn compiler API underpinning Mapperly's source generator implementation; required for understanding syntax tree manipulation
  • dotnet/runtime — Core .NET runtime; Mapperly targets specific SDK versions and requires understanding of C# language version features
  • riok/mapperly-docs-examples — Companion repo (if it exists) containing runnable examples for Mapperly; supports the documentation site

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add missing analyzer diagnostic documentation for RMG codes 000-059 and 061-065

The docs/docs/configuration/analyzer-diagnostics directory only contains RMG060, RMG066, RMG096-099. A source generator for object mappings likely has 100+ diagnostic codes. Contributing documentation for missing diagnostic codes would help users understand error messages. This is high-value because users encountering unmapped diagnostics will search for guidance.

  • [ ] Audit source code in src/ directory to identify all RMG diagnostic codes
  • [ ] Create individual .mdx files for missing diagnostics (e.g., RMG001.mdx through RMG059.mdx, RMG061-065.mdx)
  • [ ] Document each diagnostic with: error code, cause, example code that triggers it, and resolution steps
  • [ ] Update docs/docs/configuration/analyzer-diagnostics/index.mdx to include comprehensive diagnostic code reference
  • [ ] Verify all diagnostic codes referenced in actual C# source match documentation

Add end-to-end integration tests for documentation examples

The docs directory has extensive configuration examples (flattening.md, enum.mdx, external-mappings.mdx, ctor-mappings.md, etc.) but there's no apparent test suite validating that these documented examples actually compile and work. This prevents documentation drift and ensures examples in docs match current code behavior.

  • [ ] Create a new test project (e.g., tests/Riok.Mapperly.IntegrationTests.Docs/) that extracts code snippets from .md/.mdx files
  • [ ] Set up test cases that compile and verify each documented configuration example
  • [ ] Add tests for at least: configuration/flattening.md, configuration/derived-type-mapping.md, configuration/external-mappings.mdx, configuration/ctor-mappings.md
  • [ ] Integrate test execution into .github/workflows/test.yml
  • [ ] Document the approach in CONTRIBUTING.md for future doc additions

Add performance regression detection to benchmark workflow

benchmarks/Riok.Mapperly.Benchmarks/ exists with MappingBenchmarks.cs and SourceGeneratorBenchmarks.cs, but .github/workflows/benchmark.yml likely doesn't fail CI on performance regressions. Since Mapperly emphasizes minimal runtime overhead, adding baseline comparison and regression detection prevents performance degradation from merging unnoticed.

  • [ ] Review current .github/workflows/benchmark.yml workflow to understand existing benchmark execution
  • [ ] Add BenchmarkDotNet json output persistence to artifact storage (baseline comparisons)
  • [ ] Implement a step that compares current benchmark results against main branch baseline
  • [ ] Configure threshold-based failure (e.g., fail if throughput decreases >5% for any benchmark)
  • [ ] Add benchmark result comment to PRs showing performance impact
  • [ ] Document benchmark expectations in CONTRIBUTING.md

🌿Good first issues

  • Add integration test for nested object mapping scenarios in benchmarks (currently only MappingBenchmarks.cs exists; expand test coverage for deeply nested DTO hierarchies)
  • Expand Docusaurus documentation for advanced mapping scenarios (e.g., custom type converters, value transformations); docs/docs/ has configuration but lacks examples for non-trivial mapper implementations
  • Add diagnostics/analyzer rules for common mapper mistakes (e.g., public fields without properties, unmapped required members); source generator can emit Roslyn diagnostics but none visible in file list

Top contributors

Click to expand

📝Recent commits

Click to expand
  • b45b02b — chore: upgrade deps (#2267) (latonz)
  • 5908fde — chore: upgrade dependencies (#2266) (latonz)
  • 169a2d5 — chore: small performance improvements by sealing classes (#2260) (latonz)
  • ad1c68f — docs: improve diagnostic configuration title (#2259) (latonz)
  • dd7d6f1 — Upgrade dependencies (#2258) (latonz)
  • 986ef1d — fix: add support for nullable source and additional parameters in mapping (#2257) (latonz)
  • a767d44 — chore(deps): bump the docs-dependencies group across 1 directory with 9 updates (#2255) (dependabot[bot])
  • baed47c — Bump Meziantou.Polyfill from 1.0.104 to 1.0.111 (#2249) (dependabot[bot])
  • 7cd5711 — chore(deps-dev): bump the docs-dependencies group across 1 directory with 3 updates (#2234) (dependabot[bot])
  • 402bbbd — chore(deps): bump follow-redirects from 1.15.11 to 1.16.0 in /docs (#2239) (dependabot[bot])

🔒Security observations

The Mapperly codebase demonstrates a generally solid security posture as a .NET source generator project. The repository includes a proper SECURITY.md policy for responsible vulnerability disclosure and appropriate build configurations. However, there is one concerning issue: an incomplete npm package.json configuration with cut-off overrides section that could prevent security patches from being applied correctly to transitive dependencies. The Node.js version requirement is unusually strict (24.12.0+), which may limit adoption and compatibility. The project avoids common pitfalls like exposed secrets, SQL injection risks (being a code generator), or obvious XSS vulnerabilities. Recommend: (1) Fix the malformed package.json overrides immediately and verify dependency security with npm audit, (2) Review Node.js version constraints for necessity, (3) Ensure the security contact email is properly monitored.

  • Medium · Incomplete npm package.json overrides configuration — docs/package.json - overrides section. The package.json file contains an incomplete 'overrides' section that appears to be cut off mid-configuration. This could indicate either a parsing error or incomplete security fixes. The overrides for 'serialize-javascript' and 'minimatch' are present but the configuration is malformed, which may prevent these security patches from being properly applied. Fix: Complete the overrides configuration by properly closing the JSON structure. Ensure all intended dependency overrides are present and correctly formatted. Verify that security patches for serialize-javascript (>=7.0.3) and minimatch (>=10.0.3) are actually being applied by running 'npm audit' and 'npm ls'.
  • Low · Node.js version requirement is very recent — docs/package.json - engines.node. The package.json specifies Node.js >= 24.12.0, which is a very recent version. While using recent versions is generally good for security, this high minimum version may exclude some users from stable LTS versions and could cause compatibility issues in CI/CD pipelines or corporate environments that haven't upgraded yet. Fix: Consider whether Node.js 24.12.0 is truly required for all functionality. If possible, support a broader range including LTS versions (e.g., '>=18.17.0 || >=20.0.0 || >=24.0.0') while still getting security benefits. Document the rationale for the high version requirement.
  • Low · Potential hardcoded email address for security reporting — SECURITY.md. The SECURITY.md file contains a hardcoded email address (mapperly-security@riok.ch) for reporting security vulnerabilities. While this is necessary for a security policy, ensure this email address is monitored and has appropriate access controls in place. Fix: Ensure the security contact email is actively monitored and that access is restricted to authorized personnel. Consider using a dedicated security email alias with multiple reviewers. Implement automated acknowledgment of security reports.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.