Introduction

The ansible.builtin.lineinfile module edits single lines in text files — inserting, replacing, or removing lines based on regular expressions. It's the go-to module for configuration file changes where you need to modify one specific setting without templating the entire file.

For multi-line edits, use blockinfile. For full file management, use template.

Module Parameters

ParameterTypeRequiredDescription
pathstringYesFile path to edit
linestringNo*Text to insert or replace
regexpstringNoRegex to find the line to replace
statestringNopresent (default) or absent
insertafterstringNoInsert after this regex (or EOF)
insertbeforestringNoInsert before this regex (or BOF)
createboolNoCreate file if it doesn't exist
backupboolNoCreate a backup before editing
validatestringNoCommand to validate after editing
ownerstringNoFile owner
groupstringNoFile group
modestringNoFile permissions

*Required when state: present.

Basic Usage

Replace a Line

- name: Enable password authentication in SSH
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: "^PasswordAuthentication"
    line: "PasswordAuthentication yes"
    validate: 'sshd -t -f %s'

This finds any line starting with PasswordAuthentication and replaces it entirely.

Insert a Line at End of File

- name: Add DNS server
  ansible.builtin.lineinfile:
    path: /etc/resolv.conf
    line: "nameserver 8.8.8.8"

If the line already exists, no change is made (idempotent).

Remove a Line

- name: Remove old DNS entry
  ansible.builtin.lineinfile:
    path: /etc/resolv.conf
    regexp: "^nameserver 10\.0\.0\.1"
    state: absent

Practical Examples

SSH Configuration

- name: Harden SSH configuration
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    validate: 'sshd -t -f %s'
  loop:
    - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
    - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
    - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
    - { regexp: '^#?X11Forwarding', line: 'X11Forwarding no' }
    - { regexp: '^#?AllowTcpForwarding', line: 'AllowTcpForwarding no' }
  notify: restart sshd

Kernel Parameters (sysctl.conf)

- name: Set kernel parameters
  ansible.builtin.lineinfile:
    path: /etc/sysctl.conf
    regexp: "^{{ item.key }}\\s*="
    line: "{{ item.key }} = {{ item.value }}"
  loop:
    - { key: 'net.ipv4.ip_forward', value: '1' }
    - { key: 'vm.swappiness', value: '10' }
    - { key: 'net.core.somaxconn', value: '65535' }
  notify: reload sysctl

/etc/hosts Entries

- name: Add host entries
  ansible.builtin.lineinfile:
    path: /etc/hosts
    regexp: "\\s+{{ item.hostname }}$"
    line: "{{ item.ip }}  {{ item.hostname }}"
  loop:
    - { ip: '192.168.1.10', hostname: 'db.internal' }
    - { ip: '192.168.1.20', hostname: 'web.internal' }
    - { ip: '192.168.1.30', hostname: 'cache.internal' }

Environment Variables

- name: Set JAVA_HOME
  ansible.builtin.lineinfile:
    path: /etc/environment
    regexp: "^JAVA_HOME="
    line: "JAVA_HOME=/usr/lib/jvm/java-17-openjdk"

sudoers File (with Validation)

- name: Allow deploy user to restart services
  ansible.builtin.lineinfile:
    path: /etc/sudoers.d/deploy
    line: "deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp"
    create: true
    mode: '0440'
    validate: 'visudo -cf %s'

The validate parameter is critical for sudoers — a syntax error locks you out.

Insert After/Before Specific Lines

# Insert after a specific section
- name: Add option after [mysqld] section
  ansible.builtin.lineinfile:
    path: /etc/mysql/my.cnf
    insertafter: '^\[mysqld\]'
    line: 'max_connections = 500'

# Insert before a line
- name: Add comment before setting
  ansible.builtin.lineinfile:
    path: /etc/myapp/config.conf
    insertbefore: '^max_workers'
    line: '# Performance tuning'

Create File If Missing

- name: Ensure config line exists
  ansible.builtin.lineinfile:
    path: /etc/myapp/custom.conf
    line: "log_level = info"
    create: true
    owner: root
    group: root
    mode: '0644'

Backup Before Editing

- name: Edit with backup
  ansible.builtin.lineinfile:
    path: /etc/nginx/nginx.conf
    regexp: "^\\s*worker_connections"
    line: "    worker_connections 4096;"
    backup: true

Creates a timestamped backup like nginx.conf.2024-01-15@10:30:00~.

Using Backreferences

Capture parts of the matched line and reuse them:

- name: Comment out a line (preserve content)
  ansible.builtin.lineinfile:
    path: /etc/myapp/config.conf
    regexp: '^(important_setting.*)$'
    line: '# \1'
    backrefs: true

Important: When backrefs: true, the line is only changed if the regexp matches. If no match, no change is made (unlike default behavior which appends).

- name: Update port while keeping the rest
  ansible.builtin.lineinfile:
    path: /etc/myapp/config.conf
    regexp: '^(listen\s+)\d+'
    line: '\g<1>8443'
    backrefs: true

lineinfile vs Other Modules

TaskBest Module
Change one line/settinglineinfile
Insert a block of textblockinfile
Manage entire file from templatetemplate
Simple find/replace in textreplace
Edit INI-style filescommunity.general.ini_file
Edit XML filescommunity.general.xml
Edit JSON filesansible.builtin.copy with content filter

Common Mistakes

Regexp Too Broad

# WRONG — matches any line containing 'port'
regexp: "port"

# CORRECT — match the specific setting
regexp: "^listen_port\\s*="

Missing Escape Characters

# WRONG — dot matches any character
regexp: "^192.168.1.1"

# CORRECT — escape the dots
regexp: "^192\\.168\\.1\\.1"

Using lineinfile for Multi-Line Content

# WRONG — lineinfile is for single lines
- ansible.builtin.lineinfile:
    path: /etc/config
    line: |
      line1
      line2

# CORRECT — use blockinfile for multiple lines
- ansible.builtin.blockinfile:
    path: /etc/config
    block: |
      line1
      line2

Conclusion

The lineinfile module is your surgical tool for single-line edits in configuration files. Always use regexp to find and replace existing lines (rather than appending duplicates), use validate for critical files like sshd_config and sudoers, and use backup: true for safety. For multiple settings in the same file, loop over a list of regexp/line pairs. When you need more than single-line changes, switch to blockinfile or template.