GnafLoader is a .NET 10 console application that loads a Standard Geoscape G-NAF GDA2020 release into one SQL Server address lookup table and installs a fast address-search stored procedure.
The resulting dbo.AddressLookup table contains active addresses (CONFIDENCE > -1) with:
- A formatted address label and individual address components.
- Address alias and primary/secondary relationships.
- 2021 Mesh Block and confidence information.
- Default GDA2020 longitude and latitude.
The loader follows Geoscape's documented G-NAF relationships and simplified G-NAF Core model.
- .NET 10 SDK.
- SQL Server with Full-Text Search installed.
- An existing destination database.
- A SQL account that can create and drop tables, indexes, stored procedures, and full-text objects.
sqlcmdfor installing the search script from the command line, or another SQL execution tool.
Download Geoscape G-NAF - GDA2020 from data.gov.au and extract the ZIP file.
The extracted G-NAF folder must contain a release directory with Standard and Authority Code directories, for example:
GNAFLoader/
|-- G-NAF/
| `-- G-NAF MAY 2026/
| |-- Authority Code/
| `-- Standard/
|-- src/
`-- README.md
Open src/GnafLoader/appsettings.json and configure the extracted G-NAF path and SQL Server connection string:
{
"GNAF_SOURCE": "..\\G-NAF",
"GNAF_CONNECTION_STRING": "Server=localhost;Database=OzAddresses;Integrated Security=true;TrustServerCertificate=true"
}GNAF_SOURCE may point to the outer G-NAF folder or directly to the release folder containing Standard and Authority Code. Relative paths are resolved from the process working directory. The example above assumes commands are run from src, as shown below. An absolute path may be used instead.
The settings file is copied beside the executable during build and publish. The GNAF_SOURCE and GNAF_CONNECTION_STRING environment variables, or the matching command-line options, can override these settings.
From the repository root, change to src and build the solution:
cd .\src
dotnet build .\GnafLoader.sln --configuration ReleaseValidate all required G-NAF files and headers without connecting to SQL Server:
dotnet run --project .\GnafLoader --configuration Release -- --validate-onlyFrom src:
dotnet run --project .\GnafLoader --configuration Release -- --replaceThe loader uses temporary, uniquely named SQL staging tables and removes them after loading. With --replace, the existing lookup table remains available until the replacement has loaded and indexed successfully, then the tables are swapped in a transaction.
Useful options:
--source <path>overridesGNAF_SOURCE.--connection <value>overridesGNAF_CONNECTION_STRING.--schema dboand--table AddressLookupset the destination.--batch-size 100000controls SQL bulk-copy batches.--timeout 0controls SQL command and bulk-copy timeouts; zero is unlimited.- Omit
--replaceto fail safely when the destination table already exists.
The database needs enough free space for the final lookup table and per-jurisdiction staging data during the import.
After the data load has completed, execute src/sql/SearchAddresses.sql against the destination database. From src:
sqlcmd -S localhost -E -d OzAddresses -b -i .\sql\SearchAddresses.sqlThe script creates the Full-Text Search objects and dbo.SearchAddresses. Street-type names are normalised to the abbreviations stored by G-NAF, so these searches are equivalent:
EXEC dbo.SearchAddresses @Search = N'66 king street, thorn', @Top = 10;
EXEC dbo.SearchAddresses @Search = N'66 king st, thorn', @Top = 10;@Top must be between 1 and 1,000. The final search term supports prefix matching for autocomplete.
Run SearchAddresses.sql again after every data load performed with --replace, because the loader publishes a new physical AddressLookup table.
The initial full-text population runs asynchronously. Until it completes, the procedure automatically uses the regular AddressLabel prefix index so that beginning-of-label searches still return complete results.
Check population progress with:
SELECT
FULLTEXTCATALOGPROPERTY('GnafAddressSearch', 'PopulateStatus') AS PopulateStatus,
FULLTEXTCATALOGPROPERTY('GnafAddressSearch', 'ItemCount') AS IndexedAddresses;PopulateStatus = 0 means population is idle or complete.
The component index can also be queried directly:
SELECT TOP (20)
AddressDetailPid,
AddressLabel,
Longitude,
Latitude
FROM dbo.AddressLookup
WHERE State = 'QLD'
AND LocalityName = 'BRISBANE CITY'
AND StreetName = 'QUEEN'
ORDER BY StreetNumberFirst;