Practical baseline for installing Credo in Elixir apps and umbrella apps.
Goals:
- explicit lint policy
- predictable upgrades
- low-noise default setup
- optional stricter checks later
Recommended baseline:
credo: core static analysis and style checks
Optional add-on:
ex_slop: extra opinionated checks for common LLM/code-slop patterns
Suggested posture:
- start with Credo
- add ExSlop only if the team wants the extra opinions
- keep strict mode as an audit pass first, not the initial gate
Baseline:
defp deps do
[
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
]
endOptional ExSlop:
defp deps do
[
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:ex_slop, "~> 0.2", only: [:dev, :test], runtime: false}
]
endFetch deps:
mix deps.getmix credo gen.configThat creates a root .credo.exs. Keep one named config, usually default.
Recommended structure:
%{
configs: [
%{
name: "default",
files: %{
included: [
"lib/",
"src/",
"test/",
"web/",
"apps/*/lib/",
"apps/*/src/",
"apps/*/test/",
"apps/*/web/"
],
excluded: [
~r"/_build/",
~r"/deps/",
~r"/node_modules/"
]
},
plugins: [],
requires: [],
strict: false,
parse_timeout: 5000,
color: true,
checks: %{
enabled: [
# explicit list
],
disabled: [
# explicit opt-in list
]
}
}
]
}Why explicit lists:
- upgrades stay predictable
- new checks do not silently start failing CI
- lint-policy changes are easy to review
Tradeoff:
- when upgrading Credo, someone must review release notes and decide whether to adopt new checks
This is a practical, low-drama baseline for most Elixir apps.
ExceptionNamesLineEndingsParameterPatternMatchingSpaceAroundOperatorsSpaceInParenthesesTabsOrSpaces
AliasUsageTagFIXME
AliasOrderFunctionNamesLargeNumbersMaxLineLengthModuleAttributeNamesModuleNamesParenthesesInConditionParenthesesOnZeroArityDefsPipeIntoAnonymousFunctionsPredicateFunctionNamesPreferImplicitTryRedundantBlankLinesSemicolonsSpaceAfterCommasStringSigilsTrailingBlankLineTrailingWhiteSpaceUnnecessaryAliasExpansionVariableNamesWithSingleClause
ApplyCondStatementsCyclomaticComplexityFilterCountFilterFilterFunctionArityLongQuoteBlocksMapJoinMatchInConditionNegatedConditionsInUnlessNegatedConditionsWithElseNestingRedundantWithClauseResultRejectRejectUnlessWithElseWithClauses
ApplicationConfigInModuleAttributeBoolOperationOnSameValuesDbgExpensiveEmptyEnumCheckIExPryIoInspectMissedMetadataKeyInLoggerConfigOperationOnSameValuesOperationWithConstantResultRaiseInsideRescueSpecWithStructStructFieldAmountUnsafeExecUnusedEnumOperationUnusedFileOperationUnusedKeywordOperationUnusedListOperationUnusedMapOperationUnusedPathOperationUnusedRegexOperationUnusedStringOperationUnusedTupleOperationWrongTestFilename
These keep the baseline useful without making it noisy.
Enable with params:
Credo.Check.Design.AliasUsagepriority: :lowif_nested_deeper_than: 2if_called_more_often_than: 0
Credo.Check.Readability.MaxLineLengthpriority: :lowmax_length: 120
Often disabled in the first pass:
Credo.Check.Design.TagTODOCredo.Check.Readability.ModuleDoc
Reasonable defaults:
- TODOs are often issue-tracking artifacts, not lint failures
- mandatory module docs can add churn before a codebase has settled
No plugin registration is needed. Add the checks directly to checks.enabled.
CaseTrueFalseFilterNilIdentityMapIdentityPassthroughMapIntoLiteralReduceAsMapRejectNilSortThenReverseStringConcatInReduceTryRescueWithSafeAlternativeWithIdentityDoWithIdentityElse
BlanketRescueQueryInEnumMapRepoAllThenFilterRescueWithoutReraise
Good fit:
- teams cleaning up generated or AI-assisted code
- teams that want stronger pressure toward idiomatic Elixir
Less ideal as a day-one default:
- legacy codebases with lots of existing style debt
- teams that have not yet agreed on stricter refactor rules
These are useful, but commonly better as a second-pass rollout:
Refactor.UtcNowTruncateDesign.DuplicatedCodeDesign.SkipTestWithoutCommentReadability.SpecsReadability.StrictModuleLayoutRefactor.ABCSizeRefactor.VariableRebindingWarning.MixEnvWarning.UnsafeToAtom
General rule:
- if a check creates recurring team debate, leave it opt-in until the team agrees to enforce it
Start with normal-priority issues:
mix credo --allUseful commands:
mix credo
mix credo lib/my_app/foo.ex:123
mix credo --only readability
mix credo --only warning
mix credo --strictRecommended rollout order:
- install Credo and get
mix credo --allgreen - tune noisy checks in
.credo.exs - add ExSlop if desired
- run
mix credo --strictas an audit pass - only then decide whether strict mode belongs in CI
Minimum enforcement:
- add
credotomix precommit - run
mix credoin CI
Suggested alias:
defp aliases do
[
precommit: [
"compile --warnings-as-errors",
"deps.unlock --unused",
"format",
"credo",
"test"
]
]
endOnly switch to this if the repo is already clean enough:
"credo --strict"Suggested CI gate:
mix format --check-formatted
mix credo
mix test- keep excludes narrow and intentional
- prefer fixing issues over piling up ignores
- review new Credo releases before upgrading
- when investigating a warning, use
mix credo path/to/file.ex:line - if a repo has generated code or teaching/example code, exclude only those paths, not entire top-level trees