riok/mapperly
A .NET source generator for generating object mappings. No runtime reflection.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit today
- ✓11 active contributors
- ✓Apache-2.0 licensed
Show 3 more →Show less
- ✓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.
[](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:
- 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. - 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.
- 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 |
#!/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).
⚡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 generatorDirectory.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 mergingREADME.md— Project overview and quickstart; every contributor should understand the project's core purposedocs/docs/contributing/architecture.md— Architecture documentation that explains the source generator's design and component interactionsCONTRIBUTING.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 code→Source Generator— Mapper interface definition with attributes flows to generator during compilationSource Generator→Analyzer— Generated code and configuration validated by analyzer for rule violationsAnalyzer→Developer IDE— Diagnostics (RMG error codes) surface as compiler errors/warnings in editorSource Generator→C# Compiler— Generated mapper classes emitted as source code for compilationC# Compiler→Application Runtime— Compiled mapper assemblies with zero-cost generated mapping methodsDocumentation→Developer— Configuration guides and diagnostic references help developers fix mapping issues
🛠️How to make changes
Add a New Mapping Configuration Feature
- Create feature documentation in the configuration docs folder (
docs/docs/configuration/[feature-name].mdx) - Add analyzer diagnostic documentation if validation is needed (
docs/docs/configuration/analyzer-diagnostics/RMG[NNN].mdx) - Update sidebars to register new documentation page (
docs/sidebars.js)
Add a New Analyzer Diagnostic Rule
- Create diagnostic documentation with rule code and examples (
docs/docs/configuration/analyzer-diagnostics/RMG[NNN].mdx) - Register the diagnostic in the analyzer diagnostics index (
docs/docs/configuration/analyzer-diagnostics/index.mdx) - Add test cases in the test project to verify rule behavior
Add a Performance Benchmark
- Add benchmark method to the appropriate benchmark class (
benchmarks/Riok.Mapperly.Benchmarks/MappingBenchmarks.cs) - Run benchmark suite via the benchmark workflow (
.github/workflows/benchmark.yml)
Update Documentation Site
- Create or update markdown/MDX files in docs/docs/ folder (
docs/docs/[category]/[topic].mdx) - Run prebuild script to validate documentation structure (
docs/prebuild.ts) - 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 compilationAnalyzer diagnostic validation(IDE responsiveness) — Comprehensive diagnostic system checking many rules for each mapping configuration could impact IDE responsiveness on large projectsDocumentation 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
DiagnosticDescriptorto report unmappable types or configuration issues
🔗Related repos
AutoMapper/AutoMapper— Reflection-based object mapper; direct predecessor/competitor solving the same DTO mapping problem but with runtime overheadMapsterMapper/Mapster— Expression-tree based mapper; alternative approach to zero-reflection mapping in .NET with compile-time code generationdotnet/roslyn— Roslyn compiler API underpinning Mapperly's source generator implementation; required for understanding syntax tree manipulationdotnet/runtime— Core .NET runtime; Mapperly targets specific SDK versions and requires understanding of C# language version featuresriok/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.csexists; 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
Top contributors
- @dependabot[bot] — 55 commits
- @latonz — 30 commits
- @faddiv — 6 commits
- @Demivan — 2 commits
- @baracchande — 1 commits
📝Recent commits
Click to expand
Recent commits
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.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.