EditorConfig Guide

As a Tech Lead, have you already lived this situtuation, spending hours every week leaving the same code review comments: "Please add braces to this if statement." Not because you are picky, but because inconsistent code wastes everyone's time.

This is where .editorconfig can be a time saver, for the whole team. This configuration file eliminated 30% of my code review comments and cut review time from 45 to 30 minutes per pull request.

The Problem

Without EditorConfig, code reviews looked like this:

  • Monday: "John, add braces to this if statement."
  • Tuesday: "Sarah, we use braces for single-line if statements."
  • Wednesday: "Mike, same braces issue."

It's the best way to avoid not reviewing what matters: architecture or logic. Don't wait until you've missed a critical race condition because you were focused on brace placement, to figure out that something had to change.

What is EditorConfig?

EditorConfig is a configuration file that tells every IDE in your team exactly how to format code. It works across Visual Studio, VS Code, Rider, and dozens of other editors.

One .editorconfig file in your repository root ensures everyone follows the same standards automatically"no matter which IDE they use.

Getting Started: Basic Configuration

Create a .editorconfig file in your repository root:

# Root EditorConfig file
root = true

# All files
[*]
charset = utf-8
end_of_line = crlf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

That's it. These five rules prevent countless tiny inconsistencies.

C# Specific Rules

For .NET projects, add language-specific rules:

[*.cs]
# The brace rule that saves hours in code reviews
csharp_prefer_braces = true:warning

# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true

# Indentation
csharp_indent_case_contents = true
csharp_indent_switch_labels = true

# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false

Understanding Severity Levels

EditorConfig enforces rules at different levels:

  • silent - Apply the rule without indicating it
  • suggestion - Show subtle hint (three dots)
  • warning - Show yellow squiggly line
  • error - Show red squiggly line (can break builds)

Strategic usage:

# Critical rules that prevent bugs
csharp_prefer_braces = true:warning

# Strong preferences for readability
dotnet_sort_system_directives_first = true:suggestion

# Nice-to-have
csharp_space_after_cast = false:silent

Pro tip: Start permissive with "suggestion" for most rules. Gradually increase to "warning" as your team adapts. Setting everything to "error" immediately will cause team rebellion.

Complete .NET Template

Here's my production-ready EditorConfig for .NET teams:

# EditorConfig is awesome: https://EditorConfig.org
root = true

###############################
# All Files
###############################
[*]
charset = utf-8
end_of_line = crlf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

###############################
# Code Files
###############################
[*.{cs,csx,vb,vbx}]
indent_size = 4
max_line_length = 120

###############################
# XML Config Files
###############################
[*.{config,props,targets,nuspec,resx}]
indent_size = 2

###############################
# JSON Files
###############################
[*.{json,json5}]
indent_size = 2

###############################
# YAML Files
###############################
[*.{yml,yaml}]
indent_size = 2

###############################
# Markdown Files
###############################
[*.md]
trim_trailing_whitespace = false

###############################
# C# Files
###############################
[*.cs]

# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false

# this. preferences
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning

# Language keywords vs BCL types
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning

# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
dotnet_style_readonly_field = true:warning

# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion

# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion

# Code style
csharp_prefer_braces = true:warning
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion

# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true

# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
csharp_indent_block_contents = true
csharp_indent_braces = false

# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_after_comma = true
csharp_space_before_open_square_brackets = false

# Wrapping preferences
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true

###############################
# Naming Conventions
###############################

# Interfaces must start with I
dotnet_naming_rule.interfaces_should_be_prefixed_with_i.severity = warning
dotnet_naming_rule.interfaces_should_be_prefixed_with_i.symbols = interface
dotnet_naming_rule.interfaces_should_be_prefixed_with_i.style = begins_with_i

dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.capitalization = pascal_case

dotnet_naming_symbols.interface.applicable_kinds = interface

# Private fields start with underscore
dotnet_naming_rule.private_fields_should_be_prefixed_with_underscore.severity = warning
dotnet_naming_rule.private_fields_should_be_prefixed_with_underscore.symbols = private_field
dotnet_naming_rule.private_fields_should_be_prefixed_with_underscore.style = begins_with_underscore

dotnet_naming_style.begins_with_underscore.required_prefix = _
dotnet_naming_style.begins_with_underscore.capitalization = camel_case

dotnet_naming_symbols.private_field.applicable_kinds = field
dotnet_naming_symbols.private_field.applicable_accessibilities = private

# Async methods end with Async
dotnet_naming_rule.async_methods_should_end_with_async.severity = warning
dotnet_naming_rule.async_methods_should_end_with_async.symbols = async_methods
dotnet_naming_rule.async_methods_should_end_with_async.style = ends_with_async

dotnet_naming_style.ends_with_async.required_suffix = Async
dotnet_naming_style.ends_with_async.capitalization = pascal_case

dotnet_naming_symbols.async_methods.applicable_kinds = method
dotnet_naming_symbols.async_methods.required_modifiers = async

# Constants are PascalCase
dotnet_naming_rule.constants_should_be_pascal_case.severity = warning
dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
dotnet_naming_rule.constants_should_be_pascal_case.style = pascal_case

dotnet_naming_style.pascal_case.capitalization = pascal_case

dotnet_naming_symbols.constants.applicable_kinds = field
dotnet_naming_symbols.constants.required_modifiers = const

Implementation Strategy

Week 1: Get Team Buy-In

  • Hold a 15-minute team meeting
  • Show the time savings with concrete examples
  • Emphasize: "This frees us to focus on architecture, not formatting"

Week 2: Pilot on Small Project

  • Start with a non-critical project
  • Use "suggestion" severity for everything
  • Gather feedback

Week 3: Refine Rules

  • Adjust based on team consensus
  • Document reasoning for each rule in comments
  • Find the right severity levels

Week 4: Roll Out

  • Add to main repositories
  • Update team documentation
  • Critical: Don't reformat existing code all at once"let it happen organically to preserve git history

Common Pitfalls

Starting too strict: Set everything to "error" initially. Start with "suggestion" and increase gradually.

Not explaining why: Don't just add the file"explain it's about reducing cognitive load and freeing up code reviews.

Ignoring feedback: Listen to your team. Adjust rules when it makes sense.

Mass reformatting: Never reformat the entire codebase at once. It destroys git blame and creates merge conflicts. Let formatting happen naturally as files are edited.

The real win: Code reviews now focus on architecture, logic, and edge cases"not brace placement.

Advanced Techniques

CI/CD Integration

# Azure DevOps example
- task: DotNetCoreCLI@2
  displayName: 'Build with Format Validation'
  inputs:
    command: 'build'
    arguments: '/warnaserror'

This turns warnings into errors during CI, preventing non-compliant code from being merged.

Key Takeaway

EditorConfig should be part of your starter kit for every new project. It saves time, reduces friction, and helps your team focus on what really matters.

EditorConfig isn't just about code formatting"it's about leadership. By encoding standards in a file, you:

  • Make expectations clear
  • Remove yourself as a bottleneck
  • Create space for meaningful code reviews
  • Empower your team to propose changes
  • Free up time for mentoring and architecture

Code reviews should be about learning and catching real issues, not arguing about braces. EditorConfig handles the formatting so you can focus on what matters.

Resources: