Skip to content

nftables syntax

Synopsis

nft [OPTIONS] COMMAND OBJECT [FAMILY] [TABLE [CHAIN]] [SPECIFICATION]
nft [OPTIONS] -f FILE
nft [OPTIONS] -i
ruleset ─┬─ table <family> <name>
         │    ├─ chain <name>        (base chain: type, hook, priority, policy)
         │    │    └─ rule           (expressions … statement)
         │    ├─ chain <name>        (regular chain: jump/goto target)
         │    ├─ set <name>
         │    ├─ map <name>
         │    └─ stateful objects    (counter, quota, limit, ct helper, …)
         └─ table <family> <name> …

Description

nft is the userspace command of nftables, the packet classification framework of the Linux kernel (the kernel side is called nf_tables). It parses commands or a ruleset file, compiles them into nf_tables bytecode, and sends them to the kernel over netlink. Every change made by one nft invocation, including a whole file, is applied as a single atomic transaction. Rules exist only in kernel memory: they are lost on reboot unless a service loads them from a file at boot.

nft needs the CAP_NET_ADMIN capability, so it is normally run as root or with sudo. On Debian, nft is installed in /usr/sbin, which isn't in an unprivileged user's PATH.

Checked against nftables 1.1.3 on Debian 13, 1.1.6 on Ubuntu 26.04, 1.1.5 on AlmaLinux 10 and Rocky Linux 10, and 1.1.7 on Arch Linux and Gentoo (November 2026).

Address families

Every table belongs to one address family, which determines the packets it sees and the hooks its chains can use. When a command omits the family, ip is assumed.

Family Packets Hooks
ip IPv4 prerouting, input, forward, output, postrouting
ip6 IPv6 prerouting, input, forward, output, postrouting
inet IPv4 and IPv6 as ip, plus ingress (Linux 5.10 and later)
arp ARP input, output
bridge Ethernet frames crossing a bridge prerouting, input, forward, output, postrouting
netdev Any packet on one interface ingress, egress (Linux 5.16 and later)

Tables

{add | create} table [FAMILY] NAME [{ [comment "TEXT";] [flags FLAGS;] }]
{delete | destroy | list | flush} table [FAMILY] NAME
list tables [FAMILY]
delete table [FAMILY] handle HANDLE

A table is a namespace for chains, sets, maps and stateful objects. Tables have no hook or priority of their own; only base chains do.

Command Effect
add Create the table; no error if it already exists
create Create the table; error if it already exists
delete Delete the table and everything in it
destroy As delete, but no error if it doesn't exist (nftables 1.0.7 and Linux 6.3 or later)
flush Delete all rules from every chain in the table; chains, sets and maps remain
list Print the table with its contents
Table flag Effect
dormant The table's base chains are unregistered and its rules aren't evaluated
owner Only the creating process may change the table; it is removed when that process exits (nftables 0.9.9 or later)
persist With owner: the table outlives its owner and can be taken over by a new process (nftables 1.1.0 or later)

Chains

{add | create} chain [FAMILY] TABLE NAME [{ type TYPE hook HOOK [device DEV] priority PRIORITY; [policy POLICY;] [comment "TEXT";] }]
{delete | destroy | list | flush} chain [FAMILY] TABLE NAME
rename chain [FAMILY] TABLE NAME NEWNAME
list chains [FAMILY]

A base chain has type, hook and priority and is attached to a netfilter hook, so packets enter it. A regular chain has none of these; packets reach it only by jump or goto from another chain. add chain on an existing base chain with only { policy POLICY; } changes its policy.

On the command line, the braces and semicolons must be protected from the shell, for example by single quotes:

nft add chain inet filter input '{ type filter hook input priority filter; policy drop; }'

Chain types

Type Families Hooks Purpose
filter all all Accept or drop packets; the general-purpose type
nat ip, ip6, inet prerouting, input, output, postrouting Address translation; only the first packet of each connection traverses it
route ip, ip6, inet output Re-route a locally generated packet if a rule changed fields that affect routing (marks, addresses)

Base chains in the netdev family, and ingress chains in the inet family, also need device "NAME" (or devices = { "NAME", … }).

Priorities

priority is a signed integer or a standard name. On each hook, chains run in ascending priority order, whatever table they are in; the order of chains with equal priority is undefined. A name may be offset by addition or subtraction, for example filter - 5. nat chains must have a priority greater than -200 (the priority of connection tracking).

Name Value Families Hooks
raw -300 ip, ip6, inet all
mangle -150 ip, ip6, inet all
dstnat -100 ip, ip6, inet prerouting
filter 0 ip, ip6, inet, arp, netdev all
security 50 ip, ip6, inet all
srcnat 100 ip, ip6, inet postrouting

The bridge family uses different values: dstnat -300 (prerouting), filter -200 (all), out 100 (output), srcnat 300 (postrouting).

Policies

Policy Effect on a packet that reaches the end of the base chain
accept Accepted by this chain (the default). Later chains on the same hook still see it.
drop Dropped

Regular chains have no policy; at their end, evaluation returns to the calling chain.

Rules

{add | insert} rule [FAMILY] TABLE CHAIN [handle HANDLE | index INDEX] MATCH… STATEMENT… [comment "TEXT"]
replace rule [FAMILY] TABLE CHAIN handle HANDLE MATCH… STATEMENT… [comment "TEXT"]
{delete | reset} rule [FAMILY] TABLE CHAIN handle HANDLE
Command Effect
add Append to the chain, or place after the rule given by handle or index
insert Prepend to the chain, or place before the rule given by handle or index
replace Replace the rule with this handle
delete Delete the rule with this handle
reset Reset stateful statements (counters, quotas) in the rule (nftables 1.0.7 or later)

Each rule has a numeric handle, shown by nft -a list …. Within a rule, matches are evaluated left to right and all must be true; the statements then run in order. A rule with no match applies to every packet. Rules in a chain are evaluated top to bottom until a verdict ends evaluation of the chain.

Operators and values

Form Example
Equality (implicit) tcp dport 22
==, !=, <, >, <=, >= (or eq, ne, lt, gt, le, ge) tcp dport != 22, meta length > 1000
Range tcp dport 1024-65535
Prefix ip saddr 192.0.2.0/24
Anonymous set tcp dport { 80, 443 }
Named set ip saddr @blocklist
Flags tcp flags syn, ct state established,related

Common matches

Expression Matches Example values
ip saddr, ip daddr IPv4 source or destination address 192.0.2.10, 198.51.100.0/24
ip protocol IPv4 protocol field tcp, udp, icmp
ip6 saddr, ip6 daddr IPv6 source or destination address 2001:db8::/32
ip6 nexthdr IPv6 next header field (the first extension header, if any) tcp, ipv6-icmp
tcp sport, tcp dport TCP source or destination port; implies TCP 22, ssh, 8000-8999
tcp flags TCP flags syn, syn,ack, fin, rst
udp sport, udp dport UDP source or destination port; implies UDP 53, 123
th sport, th dport Port of any transport protocol with ports at the usual offset 53
icmp type ICMP message type echo-request, destination-unreachable
icmpv6 type ICMPv6 message type echo-request, nd-neighbor-solicit, nd-router-advert
ct state Connection tracking state new, established, related, invalid, untracked
ct status Connection tracking status bits dnat, snat, assured
ct mark Connection mark 0x1
iif, oif Input or output interface, by index (resolved when the rule is loaded) lo, "eth0"
iifname, oifname Input or output interface, by name (compared per packet; supports * suffix) "eth0", "wg*"
meta l4proto Transport protocol after any IPv6 extension headers tcp, udp, icmp, ipv6-icmp
meta nfproto Protocol family, in inet tables ipv4, ipv6
meta mark Packet mark 0x1
meta pkttype Link-layer packet type host, broadcast, multicast
meta skuid, meta skgid Owner of the sending socket (output hook) 0, www-data

iif fails to load if the interface doesn't exist; iifname works for interfaces created later, at a small cost per packet.

Statements

Verdicts

Statement Effect
accept Stop evaluating this chain and let the packet continue to the next base chain on the hook
drop Discard the packet; no further chain sees it
reject Discard the packet and send an error: ICMP port unreachable by default
reject with tcp reset Answer TCP with a reset segment
reject with icmp TYPE, reject with icmpv6 TYPE Answer with the given ICMP or ICMPv6 code (for example admin-prohibited)
reject with icmpx TYPE Family-independent code for inet tables (port-unreachable, admin-prohibited, no-route, host-unreachable)
jump CHAIN Evaluate the regular chain CHAIN, then return to the next rule here
goto CHAIN Evaluate CHAIN and don't return
return Return to the calling chain; at the end of a base chain, apply the policy
continue Continue with the next rule (the implicit behaviour)
queue Pass the packet to a userspace program through nfnetlink_queue

reject is valid only in base chains on the prerouting, input, forward and output hooks, and in regular chains called only from them.

Other statements

Statement Syntax Effect
counter counter Count packets and bytes that reach it; shown as counter packets N bytes N
log log [prefix "TEXT"] [level LEVEL] [flags FLAGS] Write packet details to the kernel log; log group N sends to nflog instead
limit limit rate [over] N/UNIT [burst N packets] Match while under (or, with over, above) a rate; UNIT is second, minute, hour or day; byte rates use N kbytes/second
ct ct mark set VALUE, ct helper set "NAME" Set connection tracking properties
meta meta mark set VALUE Set packet metadata
notrack notrack Exclude the packet from connection tracking (priority raw chains)
snat, dnat snat to 203.0.113.1, dnat to 192.0.2.10:8080 Source or destination address translation (nat chains)
masquerade masquerade Source NAT to the address of the outgoing interface
redirect redirect to :8080 Destination NAT to the local host

Statements are non-terminal unless they are verdicts, so counter, log and limit are usually combined with one: tcp dport 22 limit rate 10/minute counter accept.

Sets and maps

add set [FAMILY] TABLE NAME { type TYPE | typeof EXPRESSION; [flags FLAGS;] [timeout TIME;] [size N;] [elements = { … };] }
add map [FAMILY] TABLE NAME { type TYPE : TYPE | typeof EXPRESSION : EXPRESSION; [flags FLAGS;] [elements = { KEY : VALUE, … };] }
{add | delete | destroy} element [FAMILY] TABLE SET { ELEMENT, … }
{list | flush | delete} {set | map} [FAMILY] TABLE NAME
Kind Example Notes
Anonymous set tcp dport { 22, 80, 443 } accept Part of one rule; can't be changed without replacing the rule
Named set ip saddr @blocklist drop Defined in the table; elements can be added or removed at any time
Map dnat ip to tcp dport map { 80 : 192.0.2.10, 443 : 192.0.2.11 } Looks up a value from a key; in an inet table, NAT statements name the family (dnat ip, dnat ip6)
Verdict map tcp dport vmap { 22 : accept, 23 : drop } Looks up a verdict from a key

Common element types:

Type Values Equivalent typeof
ipv4_addr IPv4 addresses ip saddr
ipv6_addr IPv6 addresses ip6 saddr
inet_service Port numbers tcp dport
inet_proto Protocol numbers meta l4proto
ifname Interface names iifname
ether_addr MAC addresses ether saddr
mark Marks meta mark
TYPE . TYPE Concatenation, for example ipv4_addr . inet_service ip saddr . tcp dport
Set flag Effect
interval Elements may be ranges or prefixes
timeout Elements can expire; a per-element timeout may be given
dynamic The ruleset may add elements from the packet path (with add @set { … } or update @set { … })
constant Elements can't change after creation

The nft command

Commands

Command Effect
nft list ruleset [FAMILY] Print every table, chain, rule, set and map
nft list tables, nft list chains, nft list sets Print objects of one kind
nft list table FAMILY TABLE Print one table
nft list chain FAMILY TABLE CHAIN Print one chain
nft list set FAMILY TABLE SET Print one set with its elements
nft list hooks [FAMILY] Print every function registered on each hook, with priorities
nft flush ruleset [FAMILY] Delete all tables (and so everything else)
nft add …, insert …, create …, replace …, delete …, destroy …, flush …, reset …, rename … Change objects, as described in the sections above
nft monitor [new \| destroy] [OBJECTS] Print ruleset changes as they happen; nft monitor trace prints packets marked with meta nftrace set 1
nft describe EXPRESSION Print the data type and accepted values of an expression

Options

Option Effect
-f FILE, --file FILE Read commands or a ruleset from FILE (- for standard input)
-c, --check Parse and validate, including in the kernel, without applying the changes
-i, --interactive Read commands from an interactive prompt
-D NAME=VALUE, --define NAME=VALUE Define a variable for the ruleset
-I DIR, --includepath DIR Add a directory searched by include; the built-in default is /etc on Debian, Ubuntu, AlmaLinux, Rocky Linux and Gentoo, and /usr/share on Arch
-o, --optimize Report and apply rule merges, for example rules that differ only in port
-a, --handle Show handles in listings
-s, --stateless Omit stateful information of rules and stateful objects, such as counter values, from listings
-t, --terse Omit set elements from listings
-n, --numeric Print addresses, ports and other values numerically
-p, --numeric-protocol Print layer 4 protocols numerically
-T, --numeric-time Print time values numerically
-u, --guid Print UIDs and GIDs as names from /etc/passwd and /etc/group
-y, --numeric-priority Print chain priorities as numbers
-S, --service Translate ports to service names from /etc/services
-N, --reversedns Translate addresses to host names
-e, --echo Print objects as they are added, including their handles
-j, --json Read or write the JSON format described in libnftables-json(5)
-d LEVEL, --debug LEVEL Print debugging output (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)
-v, --version Print the version
-V Print the version with build details

Ruleset file

A ruleset file uses the same syntax as nft list ruleset prints, so a listing can be saved and loaded back. Loading a file with nft -f is one transaction: if any line fails, none of it is applied.

#!/usr/sbin/nft -f

# Start from an empty ruleset, so reloading doesn't duplicate rules.
flush ruleset

define ssh_port = 22
define admins_v4 = { 192.0.2.0/24 }
define admins_v6 = { 2001:db8:10::/48 }

table inet filter {
    set blocklist {
        type ipv4_addr
        flags interval
        elements = { 198.51.100.0/24 }
    }

    chain input {
        type filter hook input priority filter; policy drop;

        ct state vmap { established : accept, related : accept, invalid : drop }
        iif lo accept
        ip saddr @blocklist counter drop
        meta l4proto { icmp, ipv6-icmp } accept
        tcp dport $ssh_port accept
        ip saddr $admins_v4 tcp dport 8080 accept
        ip6 saddr $admins_v6 tcp dport 8080 accept
    }

    chain forward {
        type filter hook forward priority filter; policy drop;
    }

    chain output {
        type filter hook output priority filter; policy accept;
    }
}

include "/etc/nftables.d/*.nft"
Element Meaning
#!/usr/sbin/nft -f Lets the file be run as a script; ignored by nft -f
# Starts a comment
flush ruleset Removes the existing ruleset in the same transaction, so the file replaces it
define NAME = VALUE A variable, used as $NAME
include "PATH" Inserts another file; relative paths are searched in the include path; wildcards are allowed
Newline or ; Separates statements and declarations
table … { … } Block form of add table, add chain, add rule, add set

A set holds elements of one type, so IPv4 and IPv6 addresses need separate sets, variables and rules, as with $admins_v4 and $admins_v6 above.

Files

Path Distribution Purpose
/etc/nftables.conf Debian, Ubuntu, Arch Ruleset loaded by nftables.service
/etc/sysconfig/nftables.conf RHEL, AlmaLinux, Rocky Linux Ruleset loaded by nftables.service; by default it contains only a commented-out include of the examples in /etc/nftables/
/var/lib/nftables/rules-save Gentoo Ruleset saved by rc-service nftables save and loaded by /etc/init.d/nftables (OpenRC), or saved by nftables-store.service and loaded by nftables-load.service (systemd profile)
/etc/conf.d/nftables Gentoo (OpenRC) Settings for the init script, such as the save file and whether to save on stop
/etc/nftables/rules/main.nft Gentoo (systemd profile) Ruleset loaded by Gentoo's nftables.service, which starts only if this file exists; an alternative to nftables-load.service and nftables-store.service
/usr/share/doc/nftables/examples/ Debian, Ubuntu, Arch, AlmaLinux, Rocky Linux Example rulesets
/usr/share/doc/nftables-VERSION/examples/ Gentoo Example rulesets
/usr/share/nftables/ Arch, Gentoo Example rulesets
/etc/nftables/ RHEL, AlmaLinux, Rocky Linux Example rulesets, which /etc/sysconfig/nftables.conf can include

On Debian, Ubuntu and RHEL, nftables.service runs nft -f on its file when it starts or reloads, and flushes the whole ruleset when it stops. On Arch, the unit only runs nft -f /etc/nftables.conf when it starts; it has no reload or stop action. On RHEL and its rebuilds, firewalld is the default firewall and nftables.service is normally disabled; enabling both makes them overwrite each other's rules.

See also