mkdir creates directories. It’s simple, but two options, -p and -m, cover most real-world needs, and brace expansion turns it into a quick way to build whole directory trees.

mkdir [options] DIRECTORY...

Create a directory

mkdir backups
mkdir /srv/app
mkdir logs cache tmp          # several at once

Relative paths are created inside your current directory (pwd).

Create nested directories with -p

mkdir -p /var/www/example.com/public

Without -p, this fails if /var/www/example.com doesn’t exist yet. -p (parents) does two things:

  • creates every missing parent directory;
  • doesn’t fail if the directory already exists.

The second point makes mkdir -p the standard choice in scripts, Dockerfiles and deployment steps, because running it twice is harmless.

Set permissions at creation with -m

mkdir -m 700 ~/.secrets            # only you can access it
mkdir -m 2775 /srv/shared          # group-writable, setgid so new files inherit the group

Without -m, the new directory’s mode is 777 minus your umask. That’s usually 755 (umask 022) or 775 (umask 002). Note that with -p, -m applies only to the final directory. The parents get the default mode.

The octal modes are explained in chmod and Linux permissions.

Build directory trees with brace expansion

The shell expands braces before mkdir runs:

mkdir -p project/{src,tests,docs}
mkdir -p /srv/app/{releases,shared/{storage,logs},config}
mkdir -p backups/2026-{01..12}

The second line creates:

/srv/app/releases
/srv/app/shared/storage
/srv/app/shared/logs
/srv/app/config

Don’t put spaces inside the braces. {src, tests} won’t expand.

Verbose output

mkdir -pv /srv/app/shared/logs
# mkdir: created directory '/srv/app'
# mkdir: created directory '/srv/app/shared'
# mkdir: created directory '/srv/app/shared/logs'

Ownership: directories for services

Directories you create with sudo mkdir belong to root. A web server or app user usually needs ownership of its own directories:

sudo mkdir -p /var/www/example.com/public
sudo chown -R deploy:www-data /var/www/example.com

Or create and set ownership and mode in one step with install:

sudo install -d -o deploy -g www-data -m 2775 /var/www/example.com/public

install -d is handy in scripts and provisioning. For directories that services need under /run or /var/lib, systemd can create them for you: RuntimeDirectory=, StateDirectory= and LogsDirectory= in the unit file. See chown.

Temporary directories

For scratch space in scripts, use mktemp instead of a fixed name:

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

This avoids name clashes and race conditions, and the trap cleans up when the script exits.

Common errors

mkdir: cannot create directory 'x': No such file or directory — a parent directory is missing. Add -p.

mkdir: cannot create directory 'x': File exists — something with that name already exists. It might be a file, not a directory. Check with ls -ld x. Use -p if an existing directory is fine.

mkdir: cannot create directory 'x': Permission denied — you can’t write to the parent directory. Use sudo, or create it somewhere you own. Then fix ownership if a service needs it.

No space left on device even though df -h shows free space — the filesystem may be out of inodes. Check with df -i. See disk full troubleshooting.

Read-only file system — the filesystem was remounted read-only, often after disk errors. Check dmesg and the provider console.

Removing directories

rmdir dir removes an empty directory. rmdir -p a/b/c removes c, then b, then a, as long as each is empty. For directories with contents, use rm -r. See the rm command.

Quick reference

Task Command
Create dir mkdir name
Nested, no error if exists mkdir -p a/b/c
With permissions mkdir -m 750 name
Several / tree mkdir -p app/{src,logs}
Show what was created mkdir -pv path
With owner and mode install -d -o user -g group -m 755 path
Temporary dir mktemp -d

Related: ls, cp and mv.

  • Linux
  • Command Line
  • Basics