Designing Minimal RTTI Usage in Delphi Applications
Learn how to enable just enough Delphi RTTI for reflection‑based workloads while keeping binaries small and data private.
27 Sept 2026, 03:09 UTC

Requirements
When a Delphi application needs to inspect class members at runtime—for serialization, ORM mapping, or IDE designers—the Run‑Time Type Information (RTTI) subsystem must be present for the relevant types. The goal is to enable just enough RTTI to satisfy those consumers while keeping the binary size low and avoiding unintended exposure of private data.
Smallest Suitable Design
The minimal RTTI footprint is achieved by:
- Declaring the class in a unit where
$RTTIis explicitly controlled. - Marking only the members that reflection‑based code needs as
published(or using an explicit$RTTIdirective to include specific visibility). - Keeping all other fields, methods, and properties at
privateorprotectedso they are omitted from the RTTI block by default.
Example unit:
unit MyDto;
interface
uses
System.Rtti;
type
TPerson = class
private
FID: Integer; // not exposed by default
FSecret: string; // stays hidden
published
// Only these members appear in RTTI
property Name: string read FName write FName;
property Age: Integer read FAge write FAge;
end;
implementation
{$RTTI EXPLICIT METHODS([]) PROPERTIES([vcPublished]) FIELDS([])}
// The above line tells the compiler to emit RTTI only for published properties.
// Methods and fields are omitted even if they were published.
end.
With the $RTTI EXPLICIT directive the compiler emits metadata for the exact set of members listed, producing the smallest possible RTTI block for TPerson.
Trust/Data Boundaries
By default Delphi RTTI includes only published members. Private and protected data remain invisible to TRttiContext unless the $RTTI directive is expanded to include those visibilities. This creates a clear trust boundary: reflection‑based code can only see what the developer has explicitly marked as published (or added via an explicit RTTI rule). Expanding RTTI to ALL or PRIVATE would breach that boundary and could leak sensitive fields such as FSecret in the example.
Operational Checks
To verify that the intended RTTI is present:
- Runtime check – Use
TRttiContextto query the type:
var
Ctx: TRttiContext;
Typ: TRttiType;
Prop: TRttiProperty;
begin
Ctx := TRttiContext.Create;
try
Typ := Ctx.GetType(TPerson);
if Typ = nil then
raise Exception.Create('RTTI not emitted for TPerson');
// Expect only Name and Age properties
for Prop in Typ.GetProperties do
Writeln(Prop.Name); // Should print Name and Age
finally
Ctx.Free;
end;
end;
If Typ is nil, RTTI for the class was not generated.
- Binary inspection – On Windows, run
dumpbin /HEADERS MyApp.exeorobjdump -h MyAppon Linux/macOS and look for a section named.rtti. Its presence confirms that the linker included RTTI data. - Size check – Compare the file size of two builds: one with
$RTTI ON(or default) and one with$RTTI OFFfor the unit. A noticeable reduction (often several kilobytes per class) indicates that the RTTI block was omitted.
Failure Modes
- Missing RTTI – If reflection‑based code expects a property that lacks RTTI,
TRttiContext.GetTypereturnsnilorGetPropertiesreturns an empty array, leading to Access Violations when the code dereferences the nil pointer, or silent failures if the result is not checked. - Excessive RTTI – Enabling
$RTTI ALLinflates the binary, increases startup time (the loader must map a larger .rtti section), and may expose private fields, raising security concerns. - Version mismatch – Delphi 7 and earlier emit only basic RTTI (no attributes). Code that relies on newer features such as custom attributes requires Delphi 2009+; otherwise the attributes will not be visible at runtime.
Conditions That Would Change the Design
Reevaluate the minimal RTTI approach when:
- A new framework requires access to previously hidden members (e.g., an ORM that needs to map private fields). In that case, either promote those members to
publishedor add an explicit$RTTIrule for the needed visibility. - Security audits reveal that published members inadvertently expose sensitive data; then move those members to
privateand adjust the consuming code to use alternative mechanisms (e.g., explicit setter/getter methods). - Target platforms change to a Delphi version with different RTTI defaults (e.g., moving to a mobile compiler that strips RTTI by default). You may need to force RTTI emission with
$RTTI EXPLICITor adjust linking options.
By continuously matching the RTTI surface to the actual needs of reflection‑based consumers, you keep the binary lean, preserve encapsulation, and avoid the failure modes associated with missing or excessive metadata.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.