NRF stands for Network function Repository Function. Simply put, it works as a central registration center (registra) for all the Core Network Components. As shown in the following diagram, NRF has connected to all the 5G Core components in HPLMN and get connected to another NRF in VPLMN with N27 interface.
< 29.510 - Figure 4-1: 5G System architecture >

Why a network needs an NRF at all
The problem the NRF solves is easy to state. In the service based architecture any network function may need to call any other - the AMF needs the AUSF to authenticate a UE, the SMF needs the PCF for policy, almost everything needs the UDM at some point. If each of them had to be told in advance where all the others were, an operator would be maintaining a configuration file whose size grows with the
So instead every function tells one central place what it is and what it offers, and everything else asks that place. That is the NRF. It is a registry and nothing more glamorous than that :
Two things in the figure above are worth noticing. The first is that the
Followings are the name of each network component.
AMF Access and Mobility Management Function ==> Equivalent to MME in 4G AUSF Authentication Server Function DN Data Network NEF Network Exposure Function NRF Network Repository Function NSSF Network Slice Selection Function PCF Policy Control Function ==> Equivalent to PCRF in 5G (R)AN (Radio) Access Network SMF Session Management Function UDM Unified Data Management==> Equivalent to HSS in 4G UPF User Plane Function ==> Equivalent to PGW in 4G SMSF SMS Function SEAF SEcurity Anchor Function ==> part of AMF function
Since NRF is connected almost every components (Network Functions) and provide various services to all of them. Descriptions on this NF(Network Function) can be complicated. I may not be able to put all of the functionalities in this note. I will just write down those things which I have some hands-on experience with.
- NF Registration to NRF
- Example : AMF Registration
- Example : AUSF Registration
- Example : UDM Registration
- Example : UDR Registration
- Example : PCF Registration
- Example : SMF Registration
- Example : NSSF Registration
- Example : BSF Registration
- Structured Data Types
NF Registration to NRF
Each NF(Network Function) is supposed to register to NRF so that NRF can coordinate all the NFs whenever necessary.
< 29.510-Figure 5.2.2.2.2-1: NF Instance Registration >

That is the entire procedure - one request and one response - but the shape of the request is worth a moment because it explains several things you will see in the logs below.
PUT /nnrf-nfm/v1/nf-instances/{nfInstanceID} body : theNFProfile | v201 Created with the accepted NFProfile or4xx / 5xx with a ProblemDetails body or3xx a redirect to a different NRF
The practical consequence is
<hl1>NF Service Consumer</hl1> : Every Network Function (Core Network Components) except NRF itself. <hl1>URI</hl1> : The URI of the NF that wants to get registered <hl1>nfInstanceID</hl1> : UUID within the PLMN (e.g, 4947a69a-f61b-4bc1-b9da-47c9c5d14b64)
The example messages shown below is from open5gs log. (For Official documentation of open5gs, go to open5gs.org. For basic tutorial about open5gs on sharetechnote, see the notes : Installation on Virtual Machine, Installation and test on Google Cloud, WebUI, Run)
Example : AMF Registration
The AMF is the function that owns a UE's connection - it is the only part of the core with a signalling path down to the device, and everything that needs to reach a UE has to go through it. What it registers here is a single service,
PUT
07/09 21:21:05.476: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0ab51768-ffcd-41ec-a11e-7954f71c156f
(../lib/sbi/nghttp2-server.c:770)
07/09 21:21:05.476: [sbi] DEBUG: RECEIVED: 672 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:05.476: [sbi] DEBUG: {
"nfInstanceId": "0ab51768-ffcd-41ec-a11e-7954f71c156f",
"nfType": "AMF",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.5"],
"allowedNfTypes": ["SMF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "0ab6167c-ffcd-41ec-a11e-7954f71c156f",
"serviceName": "namf-comm",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.5",
"port": 7777
}],
"allowedNfTypes": ["SMF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/09 21:21:05.476: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:05.476: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:05.476: [sbi] DEBUG: {
"nfInstanceId": "0ab51768-ffcd-41ec-a11e-7954f71c156f",
"nfType": "AMF",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Example : AUSF Registration
The AUSF exists to do one job and its profile reflects that - a single service,
PUT
07/08 02:45:18.834: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/fa64abc8-fe67-41ec-b3d5-a934c5d291a8
(../lib/sbi/nghttp2-server.c:770)
07/08 02:45:18.834: [sbi] DEBUG: RECEIVED: 676 (../lib/sbi/nghttp2-server.c:773)
07/08 02:45:18.834: [sbi] DEBUG: {
"nfInstanceId": "fa64abc8-fe67-41ec-b3d5-a934c5d291a8",
"nfType": "AUSF",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.11"],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "fa64b79e-fe67-41ec-b3d5-a934c5d291a8",
"serviceName": "nausf-auth",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.11",
"port": 7777
}],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/08 02:45:18.834: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/08 02:45:18.834: [sbi] DEBUG: SENDING...: 158 (../lib/sbi/nghttp2-server.c:355)
07/08 02:45:18.834: [sbi] DEBUG: {
"nfInstanceId": "fa64abc8-fe67-41ec-b3d5-a934c5d291a8",
"nfType": "AUSF",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Example : UDM Registration
This is the most interesting profile of the eight, because the UDM registers
PUT
07/08 03:22:31.370: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/33ae29b8-fe6d-41ec-9216-8d673c526000
(../lib/sbi/nghttp2-server.c:770)
07/08 03:22:31.370: [sbi] DEBUG: RECEIVED: 1512 (../lib/sbi/nghttp2-server.c:773)
07/08 03:22:31.370: [sbi] DEBUG: {
"nfInstanceId": "33ae29b8-fe6d-41ec-9216-8d673c526000",
"nfType": "UDM",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.12"],
"allowedNfTypes": ["AMF", "SMF", "AUSF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "33ae6342-fe6d-41ec-9216-8d673c526000",
"serviceName": "nudm-ueau",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.12",
"port": 7777
}],
"allowedNfTypes": ["AUSF"],
"priority": 0,
"capacity": 100,
"load": 0
}, {
"serviceInstanceId": "33ae6360-fe6d-41ec-9216-8d673c526000",
"serviceName": "nudm-uecm",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.12",
"port": 7777
}],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0
}, {
"serviceInstanceId": "33ae636a-fe6d-41ec-9216-8d673c526000",
"serviceName": "nudm-sdm",
"versions": [{
"apiVersionInUri": "v2",
"apiFullVersion": "2.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.12",
"port": 7777
}],
"allowedNfTypes": ["AMF", "SMF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
201 Created
07/08 03:22:31.371: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/08 03:22:31.371: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/08 03:22:31.371: [sbi] DEBUG: {
"nfInstanceId": "33ae29b8-fe6d-41ec-9216-8d673c526000",
"nfType": "UDM",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Example : UDR Registration
The UDR is the storage behind the UDM, and it registers a single service,
PUT
07/09 21:21:05.726: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0adb7b56-ffcd-41ec-8ac9-0f5331342d1b
(../lib/sbi/nghttp2-server.c:770)
07/09 21:21:05.726: [sbi] DEBUG: RECEIVED: 686 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:05.726: [sbi] DEBUG: {
"nfInstanceId": "0adb7b56-ffcd-41ec-8ac9-0f5331342d1b",
"nfType": "UDR",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.20"],
"allowedNfTypes": ["PCF", "UDM"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "0adc404a-ffcd-41ec-8ac9-0f5331342d1b",
"serviceName": "nudr-dr",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.20",
"port": 7777
}],
"allowedNfTypes": ["PCF", "UDM"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/09 21:21:05.726: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:05.726: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:05.726: [sbi] DEBUG: {
"nfInstanceId": "0adb7b56-ffcd-41ec-8ac9-0f5331342d1b",
"nfType": "UDR",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Example : PCF Registration
The PCF registers
PUT
07/09 21:21:05.723: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0adae7a4-ffcd-41ec-aff0-b734789f4477
(../lib/sbi/nghttp2-server.c:770)
07/09 21:21:05.723: [sbi] DEBUG: RECEIVED: 1146 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:05.723: [sbi] DEBUG: {
"nfInstanceId": "0adae7a4-ffcd-41ec-aff0-b734789f4477",
"nfType": "PCF",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.13"],
"allowedNfTypes": ["AMF", "SMF", "NEF", "AF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "0adb8b96-ffcd-41ec-aff0-b734789f4477",
"serviceName": "npcf-am-policy-control",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.13",
"port": 7777
}],
"allowedNfTypes": ["AMF", "NEF"],
"priority": 0,
"capacity": 100,
"load": 0
}, {
"serviceInstanceId": "0adb8baa-ffcd-41ec-aff0-b734789f4477",
"serviceName": "npcf-smpolicycontrol",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.13",
"port": 7777
}],
"allowedNfTypes": ["SMF", "NEF", "AF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/09 21:21:05.723: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:05.723: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:05.723: [sbi] DEBUG: {
"nfInstanceId": "0adae7a4-ffcd-41ec-aff0-b734789f4477",
"nfType": "PCF",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Example : SMF Registration
The SMF owns PDU sessions - creating them, modifying them, tearing them down - and it controls the UPF that actually forwards the traffic. It registers one service,
PUT
07/09 21:21:06.081: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0adf454c-ffcd-41ec-9f8e-25aaf51f9b14
(../lib/sbi/nghttp2-server.c:770)
07/09 21:21:06.081: [sbi] DEBUG: RECEIVED: 678 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:06.081: [sbi] DEBUG: {
"nfInstanceId": "0adf454c-ffcd-41ec-9f8e-25aaf51f9b14",
"nfType": "SMF",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.4"],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "0b11ac76-ffcd-41ec-9f8e-25aaf51f9b14",
"serviceName": "nsmf-pdusession",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.4",
"port": 7777
}],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/09 21:21:06.081: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:06.081: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:06.081: [sbi] DEBUG: {
"nfInstanceId": "0adf454c-ffcd-41ec-9f8e-25aaf51f9b14",
"nfType": "SMF",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Example : NSSF Registration
The NSSF answers one question - which network slice instance should serve this UE - and registers one service to do it,
PUT
07/08 03:20:40.354: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/eaf3a41e-fe6c-41ec-9185-39782a1733b6
(../lib/sbi/nghttp2-server.c:770)
07/08 03:20:40.354: [sbi] DEBUG: RECEIVED: 683 (../lib/sbi/nghttp2-server.c:773)
07/08 03:20:40.354: [sbi] DEBUG: {
"nfInstanceId": "eaf3a41e-fe6c-41ec-9185-39782a1733b6",
"nfType": "NSSF",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.14"],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "eaf42bd2-fe6c-41ec-9185-39782a1733b6",
"serviceName": "nnssf-nsselection",
"versions": [{
"apiVersionInUri": "v2",
"apiFullVersion": "2.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.14",
"port": 7777
}],
"allowedNfTypes": ["AMF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/08 03:20:40.354: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/08 03:20:40.354: [sbi] DEBUG: SENDING...: 158 (../lib/sbi/nghttp2-server.c:355)
07/08 03:20:40.354: [sbi] DEBUG: {
"nfInstanceId": "eaf3a41e-fe6c-41ec-9185-39782a1733b6",
"nfType": "NSSF",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
} (../lib/sbi/nghttp2-server.c:356)
Example : BSF Registration
The BSF is the least familiar of the eight and its job is a binding problem. It registers
PUT
07/09 21:21:06.262: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0b2e7414-ffcd-41ec-9c59-a56e64429106
(../lib/sbi/nghttp2-server.c:770)
07/09 21:21:06.262: [sbi] DEBUG: RECEIVED: 680 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:06.262: [sbi] DEBUG: {
"nfInstanceId": "0b2e7414-ffcd-41ec-9c59-a56e64429106",
"nfType": "BSF",
"nfStatus": "REGISTERED",
"ipv4Addresses": ["127.0.0.15"],
"allowedNfTypes": ["PCF"],
"priority": 0,
"capacity": 100,
"load": 0,
"nfServices": [{
"serviceInstanceId": "0b2e7aa4-ffcd-41ec-9c59-a56e64429106",
"serviceName": "nbsf-management",
"versions": [{
"apiVersionInUri": "v1",
"apiFullVersion": "1.0.0"
}],
"scheme": "http",
"nfServiceStatus": "REGISTERED",
"ipEndPoints": [{
"ipv4Address": "127.0.0.15",
"port": 7777
}],
"allowedNfTypes": ["PCF"],
"priority": 0,
"capacity": 100,
"load": 0
}],
"nfProfileChangesSupportInd": true
}
201 Created
07/09 21:21:06.262: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:06.262: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:06.262: [sbi] DEBUG: {
"nfInstanceId": "0b2e7414-ffcd-41ec-9c59-a56e64429106",
"nfType": "BSF",
"nfStatus": "REGISTERED",
"heartBeatTimer": 10,
"nfProfileChangesInd": true
}
Reading the eight registrations together
Having eight of these side by side is more useful than any one of them, because the interesting thing is how little changes between them. All eight are the same request to the same endpoint carrying the same structure - and pulling out the fields that actually differ gives a very short table :
| Example | nfType | nfServices registered | heartBeat | capacity |
|---|---|---|---|---|
AMF |
namf-comm | 10 | 100 | |
AUSF |
nausf-auth | 10 | 100 | |
UDM |
10 | 100 | ||
UDR |
nudr-dr | 10 | 100 | |
PCF |
10 | 100 | ||
SMF |
nsmf-pdusession | 10 | 100 | |
NSSF |
nnssf-nsselection | 10 | 100 | |
BSF |
nbsf-management | 10 | 100 |
| Field | What it does |
|---|---|
The NF is promising to check in at least this often, in seconds. If it stops, the NRF eventually marks the profile SUSPENDED and stops handing it out. This is how a crashed function disappears from the network without anybody deregistering it - |
|
Static capability and current utilisation, both 0 to 100. The NRF returns them with a discovery result so that a consumer facing several candidates can choose the least busy one rather than always the first |
|
REGISTERED, SUSPENDED or UNDISCOVERABLE. A function can stay registered while asking not to be handed out - useful for draining it before maintenance |
|
The UUID in the request URI. It belongs to the function, not to the NRF, which is what makes re-registration after a restart safe |
The rest of the life cycle
Registration is only the first of four operations, and the logs on this page show the first one. The complete set is small :
PUT /nnrf-nfm/v1/nf-instances/{id} register, or replace the whole profilePATCH /nnrf-nfm/v1/nf-instances/{id} heartbeat, or change one field such as loadGET /nnrf-disc/v1/nf-instances?...discovery - the query other NFs actually useDELETE /nnrf-nfm/v1/nf-instances/{id} deregister, on a clean shutdown
The two management operations live under
Structured Data Types
There are various structured data type being used in communication between NF and NRF. These data types are specified in 39.510-6.1.6.2. This section is mostly direct copies of those tables that I am interested. If you don't find any of those structures, refer to 39.510
NFProfile
The NFProfile is the only thing a network function ever tells the NRF about itself. Everything the rest of the network will later be able to discover - where this function is, what it can do, which slices and PLMNs it serves, whether it is healthy, how busy it is - has to be expressible inside this one structure. That is why it runs to sixteen pages of table. It is not describing a message ; it is describing the complete vocabulary available for one function to advertise itself.
The table has five columns, and the one worth reading first is the narrow one marked
nfInstanceId M who am I - the UUID that also forms the registration URInfType M what am I - AMF, SMF, UDM and so onnfStatus M can I be used - REGISTERED, SUSPENDED, UNDISCOVERABLE everything after this isO orC
Three fields is a complete, valid registration. Everything in the remaining fifteen pages is refinement on top of that : how to reach the function (fqdn, ipv4Addresses, ipEndPoints), what it actually offers (nfServices), which slices and networks it serves (sNssais, plmnList, snpnList), how much work it can take (capacity, load, priority), and how long the NRF should wait before assuming it has died (heartBeatTimer). None of that is required, because a registry that demanded all of it could not accept a function that did not have all of it.
That is also the answer to why the table is so long relative to what you actually saw in the logs above. One structure has to serve every network function type that exists or might later be invented - an NSSF, a UPF, a charging function and an AMF all register through this same definition - so it accumulates attributes that only matter to some of them. Go back and look at any of the eight profiles earlier on this page and you are seeing a small, sensible subset : the identifiers, an address, a service list, a heartbeat and a capacity figure. The other fields are simply absent, and their absence is not an omission but the normal case.
< 29.510 - 29.510-Table 6.1.6.2.2-1: Definition of type NFProfile >
















Reference :