Freeze the string literals your application owns first
Rails application-only frozen string literals offer a useful compatibility boundary. Keep runtime settings and linter assumptions aligned before expanding it.
A default that changes how string literals behave also changes what your team must know about compatibility. Applying that default to code you own gives you a smaller area to inspect and repair. Extending it to every dependency makes the dependency graph part of the same decision. Start with the application boundary unless you have evidence that the wider boundary is appropriate.
Rails provided a useful example in its 1 May 2026 development roundup. It described a generated Bootsnap configuration that enabled frozen string literals for application code while leaving dependencies outside that setting. The accompanying linter configuration assumed the application setting was enabled. These two decisions belong together: the runtime establishes the behavior, and the linter reasons about that behavior.
The boundary follows responsibility
The underlying Rails pull request opened on 26 April and merged into main on 27 April 2026. Its author explicitly separated the application's own code from dependencies and noted that older gems might not be ready for a broader setting. That is historical evidence about a development change. A merge and a weekly announcement do not establish which installed stable Rails release contains it.
The distinction matters even if your team likes immutability as a general design principle. You can change a string mutation in your application, discuss the intended behavior with its author, and release the correction through your own process. A similar incompatibility inside a gem may require an upstream change, a version decision, or a different integration. Ownership changes the available remedies.
Application-only scope does not mean every object in the application becomes immutable. The subject is string literals under the relevant configuration. Treating this as a universal object guarantee would obscure the actual change and encourage incorrect assumptions elsewhere. A useful review starts by naming the precise behavior being changed and the files to which that behavior applies.
There is also a business reason to keep that description narrow. An engineering lead needs to know whether a maintenance task concerns owned source or an ecosystem compatibility exercise. Those have different coordination costs. A short configuration change can create a much larger investigation if its boundary is left implicit in the handover.
Runtime and linter must describe the same program
The May roundup specifically warned that disabling frozen string literals in the application also requires updating the RuboCop configuration. A linter assumption is part of the development contract. When it diverges from runtime behavior, a clean-looking source file can communicate the wrong expectations to its next maintainer.
Consider the review question rather than a particular command: does the source checker assume that literals are already frozen where the program actually runs? If the answer changes between environments, the configuration needs an explanation. Keeping the assumption in one visible policy is easier to maintain than relying on each contributor to remember an exception from an old discussion.
This does not establish that any particular linter warning, allocation reduction, or runtime failure occurred in your application. Those require evidence from that application. The source establishes the relationship between the generated settings; the maintenance recommendation is to preserve that relationship when adapting them. A generic performance claim cannot substitute for checking compatibility.
A useful configuration review therefore follows the behavior through startup and source analysis. It identifies the application scope, the intended treatment of dependencies, and the assumption passed to the linter. If the team deliberately opts out, record why both settings differ from the generated default. Future upgrades should be able to distinguish that deliberate choice from an accidental mismatch.
A global setting can be justified
The strongest objection to application-only scope is that an audited dependency graph may support a global policy. The Rails roundup itself noted that enabling the behavior for dependencies could reduce allocations. If the team understands the graph and accepts responsibility for its compatibility, a broader setting may be sensible. Restricting the scope forever would then leave a possible benefit unexplored.
The important word is audited. Confidence in the gems you happen to remember is weaker than knowledge of the dependencies actually loaded by the application. A global decision should account for the paths that matter to the product and for how future dependency changes will be assessed. The boundary moves only when the supporting responsibility moves with it.
Conversely, retaining application-only scope is reasonable when the wider investigation would cost more than the expected benefit. There is no measured saving here that forces a particular choice. Teams maintaining a stable product can prioritize a clear local policy while leaving dependencies under their existing assumptions. That is a decision about maintenance effort, rather than a rejection of immutable literals.
Make the policy survive the next upgrade
For an existing application, first establish what its installed code and startup configuration actually do. Do not infer that behavior from a headline about new applications. Then compare the source checker's assumptions with the runtime setting. Only after that comparison does it make sense to decide whether to expand the scope.
The handover should explain who owns compatibility when a dependency changes and what evidence would justify revisiting the boundary. This is the kind of focused work that belongs in software maintenance: connect a configuration choice to the code and people responsible for keeping it correct. Freeze the literals within a boundary your team can explain, and widen that boundary when the evidence supports it.
Paul