skip to content

macOS

macOS is Unix underneath with Apple's own layers on top: the XNU kernel, launchd instead of systemd, APFS, and a security model built from SIP, Gatekeeper, and TCC. Relevant for Apple-platform and developer-tooling roles.

on this pageshow

explore

questions

page 1 of 2

On macOS, what is the difference between a Launch Agent and a Launch Daemon, and how does that choice change what the job is able to do?

level: juniorimportance: must knowfreq 80%

answer

  1. one of them runs before anyone logs in
  2. session or no session
  3. root in the system domain
  4. per-login-session copies for the other
  5. LaunchDaemons versus LaunchAgents directories

basics

~20 s

A Launch Daemon runs in the system domain from boot, normally as root, with no login session and no access to a user's screen. A Launch Agent runs inside a logged-in user's session, as that user, and can reach the GUI.

solid answer

~40 s

Both are launchd jobs described by a plist; the difference is the domain launchd loads them into. A Launch Daemon lives in `/Library/LaunchDaemons` (Apple's own in `/System/Library/LaunchDaemons`), is loaded into the system domain at boot before anyone logs in, and runs as root unless the plist sets `UserName`. Having no login session, it cannot talk to the window server, so a daemon that tries to show UI just fails. A Launch Agent lives in `/Library/LaunchAgents` (for every user) or `~/Library/LaunchAgents` (for one user), and launchd starts a separate copy per login session, running as that user with their environment, keychain and GUI access. Rule of thumb: must run with nobody logged in, or needs root, means daemon; needs the user's identity or screen means agent.

go deeper

for a junior

Be able to say plainly that daemons are system-wide and start at boot as root, while agents run per logged-in user in that user's session, and name the two /Library directories.

for a middle

Explain the domain model behind the split — system domain versus a per-user domain that exists only between login and logout — and why a daemon has no window server connection.

for a senior

Show the production judgment: pick a service account with UserName instead of leaving a helper as root, and use the daemon-plus-agent split with XPC when a feature needs both privilege and a user prompt.

for a principal

Own the tradeoff for a fleet: which components genuinely need system-domain privilege, how helpers are registered and updated (installer-dropped plists versus SMAppService), and how user-toggleable background items on recent macOS affect deployability.

## Domains, not directories `launchd` is PID 1 on macOS: the kernel starts it and it starts everything else. It does not keep one global job list — it keeps *domains*, and a job only exists inside one. The two you meet constantly are the **system domain**, which exists from boot until shutdown, and a **per-user domain**, created when a user logs in and torn down when they log out. "Launch Daemon" and "Launch Agent" are simply the names for a job loaded into one or the other. The directory a plist sits in is how launchd decides which domain to use; it is a consequence of the distinction, not the distinction itself. ## Where the plists live A job is a property list whose filename is conventionally its `Label` plus `.plist`. - `/System/Library/LaunchDaemons` and `/System/Library/LaunchAgents` — Apple's own jobs. These are protected by System Integrity Protection; you do not edit them. - `/Library/LaunchDaemons` — third-party system-wide daemons. Loaded at boot, before login. Owned by root. - `/Library/LaunchAgents` — third-party agents that should exist for *every* user; one instance per login session. - `~/Library/LaunchAgents` — agents for that one user only. ## What each can actually do A daemon starts early, so it can hold a privileged port, manage a device, or run a background service that must survive logout and fast user switching. The price is isolation: there is no window server connection, no user keychain, no `$HOME` belonging to a human, and no Aqua session. Attempts to draw UI or read a user's login keychain from a daemon fail, and that is by design rather than a bug you can configure away. An agent is the mirror image. It runs as the user, inside their session, so it may show a window, post a user notification, read the login keychain, and see the user's environment. It cannot do anything the user cannot do, and it does not exist while that user is logged out. A daemon runs as root unless you set `UserName` and `GroupName` in the plist. Running a third-party daemon as root when it does not need root is the classic security finding in a macOS review — an unprivileged service account is almost always the right answer. ## The split-helper pattern When a feature needs both privilege and UI — a VPN client, a backup tool, an updater — the shipping shape is two jobs: a Launch Daemon doing the privileged work and a Launch Agent doing the talking to the user, communicating over XPC or a Mach service the daemon advertises. Trying to collapse that into one job is how people end up with a root process poking at a user's session, which is exactly the boundary macOS is drawing. ```xml <key>Label</key><string>com.example.sync</string> <key>UserName</key><string>_examplesync</string> ``` ## The modern wrinkle On macOS 13 and later, third-party daemons and agents surface to the user as background items they can switch off, so "I installed the plist and it never ran" now has a plausible answer that has nothing to do with your plist being wrong. Apple also offers `SMAppService` as the supported way for an app to register its own helper rather than dropping files into `/Library` from an installer script. ## The interview point The question is really testing whether you understand that macOS ties privilege and session together deliberately: root without a session (daemon), or a session without root (agent). Candidates who answer "the folder name is different" have memorised the surface; candidates who say "a daemon has no window server connection, so it cannot ask the user anything" have actually shipped one.

  • A privileged helper needs to ask the logged-in user to approve something. How do you structure that?
    Ship two jobs: a Launch Daemon that holds the privilege, and a Launch Agent running in the user's session that shows the UI. The daemon advertises a Mach service (a `MachServices` entry) and the agent connects to it over XPC. The daemon never tries to draw anything itself.
  • If two users are logged in simultaneously, how many copies of an agent in /Library/LaunchAgents are running?
    One per login session, so two — each running as its own user in its own per-user domain. That matters for anything that assumes exclusive ownership of a file, a port or a lock: an agent must tolerate a sibling copy running as somebody else at the same time.
  • What user does a Launch Daemon run as if the plist says nothing about it?
    root. Set `UserName` (and usually `GroupName`) to drop it to a dedicated service account unless the job genuinely needs root — for example to bind a low port, touch system state, or manage a device. An unnecessary root daemon is a standard audit finding.

saying these in an interview costs you the question

  • Thinks a Launch Daemon can show a dialog to the user
  • Says agents and daemons differ only by folder name
  • Believes a Launch Agent starts at boot before login
  • Assumes a job in ~/Library/LaunchAgents runs as root
  • Expects one agent instance no matter how many users log in

context

open as a page

On macOS, an app downloaded through a web browser is blocked on first launch, but the identical file fetched with curl opens immediately. What mechanism explains the difference?

level: juniorimportance: must knowfreq 66%

basics

~20 s

The browser tags its download with the com.apple.quarantine extended attribute; curl does not. Gatekeeper only evaluates quarantined files, so the tagged copy is checked for a valid signature and notarization on first launch while the untagged copy simply runs.

open as a page

On a Mac formatted with APFS, why do several volumes on the same startup disk each report roughly the same amount of free space, and what is the relationship between an APFS container and the volumes inside it?

level: middleimportance: must knowfreq 65%

basics

~20 s

An APFS container owns all the blocks of its partition, and every volume inside it allocates from that one shared free pool. Volumes therefore have no fixed size, and each reports the container's remaining space as its own available space.

open as a page

On an Apple Silicon Mac, Homebrew installs under /opt/homebrew instead of the /usr/local prefix it uses on Intel Macs. Why does that split exist, and what has to be configured before the shell finds brew-installed commands?

level: middleimportance: must knowfreq 64%

basics

~20 s

Homebrew uses a separate /opt/homebrew prefix on Apple Silicon so an arm64 installation can coexist with an Intel one under /usr/local and so bottles are built for a known default prefix. That directory is not on the default PATH, so brew shellenv must add it.

open as a page

macOS runs the XNU kernel. What does it mean that XNU is a hybrid kernel, and how is that different from monolithic Linux?

level: middleimportance: must knowfreq 68%

basics

~20 s

XNU combines a Mach core providing tasks, threads, port-based IPC and virtual memory with a BSD layer providing POSIX syscalls, processes, VFS and the network stack, plus IOKit for drivers. All of it runs in one kernel address space, so it is hybrid in structure but monolithic in performance.

open as a page

In a macOS launchd job plist, what do the RunAtLoad and KeepAlive keys each control, and how do they differ?

level: middleimportance: must knowfreq 68%

basics

~20 s

RunAtLoad is a start trigger: launchd runs the job once, immediately, when the job is loaded. KeepAlive is a restart policy: launchd keeps the job running and starts it again whenever it exits. Both default to false.

open as a page

On macOS, why can a process running as root still be denied when it writes to /System or /usr/bin, and what enforces that?

level: middleimportance: must knowfreq 68%

basics

~20 s

System Integrity Protection (SIP) is a kernel policy that marks paths such as /System, /bin, /sbin and /usr (excluding /usr/local) as restricted. The kernel denies writes there regardless of uid, so root has no special power.

open as a page

On macOS, you edit an application's preferences .plist file in ~/Library/Preferences by hand while the app is running, and your change disappears. Why, and what is the supported way to set that preference?

level: middleimportance: must knowfreq 55%

basics

~20 s

The preferences daemon cfprefsd owns those files, caches each domain in memory, and flushes its own copy back to disk — overwriting a hand edit. Use the defaults command (or the CFPreferences API), which goes through cfprefsd, then restart the app that reads the setting.

open as a page

A macOS build machine reports its disk is nearly full, but deleting tens of gigabytes of files barely moves the free-space number. How do APFS snapshots explain this, and what actually releases the space?

level: seniorimportance: must knowfreq 52%

basics

~20 s

APFS snapshots still reference the deleted files' blocks, so removing a file only unlinks it from the live volume and frees nothing. The space returns when the snapshots holding those blocks are thinned or deleted.

open as a page

Duplicating a 20 GB file on an APFS volume in macOS finishes almost instantly and the disk's free space barely changes. What did the filesystem actually do, and when is that space eventually consumed?

level: juniorimportance: should knowfreq 58%

basics

~20 s

APFS made a clone: a second file record pointing at the same on-disk extents rather than a byte-for-byte copy. Space is only consumed later, block by block, as one of the two copies is modified and diverges.

open as a page

In Homebrew on macOS, what is the difference between a formula and a cask, and where does each kind of package end up on disk?

level: juniorimportance: should knowfreq 62%

basics

~20 s

Homebrew formulae are command-line packages that Homebrew builds or downloads as a prebuilt bottle into its own prefix and symlinks onto PATH. Casks are pre-built macOS applications and installers that Homebrew downloads and places in /Applications.

open as a page

What is Darwin, and what does it mean for portability that macOS runs the XNU kernel rather than the Linux kernel?

level: juniorimportance: should knowfreq 50%

basics

~20 s

Darwin is the open-source core of macOS: the XNU kernel plus a BSD-derived userland. Because XNU is not Linux, POSIX code ports easily, but Linux-only interfaces such as /proc, epoll, inotify, cgroups and namespaces simply do not exist there.

open as a page

On a Mac you have only shell access to, how do you determine the macOS version and whether the hardware is Apple Silicon or Intel — and what can make each of those checks report the wrong thing?

level: juniorimportance: should knowfreq 58%

basics

~20 s

Use sw_vers for the macOS product version and build, uname -m for the CPU architecture (arm64 on Apple Silicon, x86_64 on Intel), and system_profiler SPHardwareDataType for model, chip and serial number. Rosetta translation can make uname -m report x86_64 on an Apple Silicon machine.

open as a page

When a Mac's startup disk moved from HFS+ to APFS, which concrete behaviours changed for applications and for people administering the machine?

level: middleimportance: should knowfreq 45%

basics

~20 s

APFS replaced HFS+ journaling with copy-on-write metadata, added clones, snapshots and volumes that share a container's free space, gave timestamps nanosecond resolution instead of one second, made encryption native and per-volume, and dropped support for directory hard links.

open as a page

A shell script that works on a Linux CI runner fails on a developer's Mac at the line `sed -i 's/foo/bar/' config.txt`. Why does macOS behave differently here, and what are the portable ways to fix it?

level: middleimportance: should knowfreq 52%

basics

~20 s

macOS ships a BSD userland, not GNU coreutils, and BSD sed requires an explicit backup-suffix argument after -i. It reads 's/foo/bar/' as that suffix and then tries to parse the filename as the script, so the command fails.

open as a page

macOS has shipped zsh as the default login shell since Catalina, yet /bin/bash on a current Mac is still version 3.2. Explain both facts and what they mean for shell scripts you ship to Macs.

level: middleimportance: should knowfreq 54%

basics

~20 s

Apple made zsh the default login shell in macOS Catalina and kept bash only as a legacy interpreter, frozen at 3.2 because that is the last release under GPLv2 and Apple does not ship GPLv3 software. Scripts with a /bin/bash shebang therefore run on a 2007 bash.

open as a page

On macOS, what is a kernel extension (kext), and why has Apple pushed third-party drivers out of the kernel into System Extensions and DriverKit?

level: middleimportance: should knowfreq 40%

basics

~20 s

A kext is code loaded into the XNU kernel's own address space, historically an IOKit driver or a filesystem. Because a defect there panics or compromises the whole machine, Apple deprecated third-party kexts in favour of System Extensions and DriverKit, which run the same logic as userspace processes.

open as a page

How does a launchd job scheduled with StartCalendarInterval behave differently from the same schedule in cron when the Mac is asleep at the scheduled time?

level: middleimportance: should knowfreq 46%

basics

~20 s

cron simply misses the run: a sleeping machine has no cron tick, and the moment passes. launchd remembers, and runs the job when the Mac wakes. If several intervals were missed, launchd coalesces them into a single run rather than firing once per missed slot.

open as a page

What is an entitlement on macOS, and how do the App Sandbox and the Hardened Runtime use entitlements differently?

level: middleimportance: should knowfreq 46%

basics

~20 s

An entitlement is a key/value claim embedded in a program's code signature that the kernel and system services consult at runtime. The App Sandbox uses entitlements to widen a default-deny confinement; the Hardened Runtime uses them to relax protections it otherwise switches on.

open as a page

A colleague adds a nameserver line to /etc/resolv.conf on a Mac and reports that DNS resolution is unchanged for their apps. Why does that happen on macOS, and how do you actually change and inspect the system's DNS configuration?

level: middleimportance: should knowfreq 42%

basics

~20 s

On macOS /etc/resolv.conf is generated from the SystemConfiguration store, not read as the source of truth; the system resolver goes through mDNSResponder using per-interface settings. Change DNS with networksetup -setdnsservers (or the network settings UI) and inspect the real configuration with scutil --dns.

open as a page

On a Mac with Apple silicon or a T2 chip, the internal APFS storage is already encrypted by hardware. What does turning on FileVault actually change, and what does it not protect against?

level: seniorimportance: should knowfreq 42%

basics

~20 s

FileVault binds the APFS volume's encryption key to user credentials, so the data cannot be unlocked without someone authenticating. The hardware already encrypts at rest; without FileVault the keys are released without a password. It protects nothing on a running, unlocked machine.

open as a page

After a macOS major upgrade, a developer's `git` and `cc` commands start failing with `xcrun: error: invalid active developer path`. What are /usr/bin/git and /usr/bin/cc actually doing on macOS, and how do you fix and pin that toolchain?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The tools in /usr/bin are thin shims that locate the real binaries through xcrun in the active developer directory. A macOS upgrade removes or invalidates that directory, so the shims fail until the Command Line Tools are reinstalled or xcode-select points at a valid path.

open as a page

Why is issuing raw system-call traps on macOS unsafe, and what does Apple treat as the stable kernel ABI instead?

level: seniorimportance: should knowfreq 30%

basics

~20 s

On macOS the stable interface is libSystem, not the trap numbers. Apple reserves the right to change or renumber system calls between releases, so a binary that traps into the kernel directly can break on a future macOS version. Every macOS binary links libSystem dynamically; there is no supported static libc.

open as a page

On modern macOS, how do launchctl bootstrap and bootout differ from the older launchctl load and unload, and what does a service target such as system/com.example.job or gui/501/com.example.agent identify?

level: seniorimportance: should knowfreq 50%

basics

~20 s

bootstrap and bootout are the domain-aware commands: you name the domain explicitly, such as system or gui/501, and launchctl loads or removes the job there. load and unload are the legacy spelling that infers the domain from context, and they are kept only for compatibility.

open as a page

A macOS Launch Daemon configured with KeepAlive crashes a second after it starts, every time. What does launchd do about it, and what keeps it from respawning the process in a tight loop?

level: seniorimportance: should knowfreq 42%

basics

~20 s

launchd keeps restarting it, but rate-limits the respawns: a job is not started more often than once per ThrottleInterval, ten seconds by default. So a crash loop shows up as a process reappearing roughly every ten seconds, not as a spinning CPU.

open as a page

On an Apple Silicon Mac, a freshly compiled arm64 binary dies immediately with "Killed: 9" while the same source runs fine on an Intel Mac. What is happening?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Apple Silicon requires every arm64 executable to carry a valid code signature. The kernel refuses to execute unsigned or signature-broken arm64 code and kills the process with SIGKILL at exec, before any of its code runs. An ad-hoc signature satisfies the requirement.

open as a page

A script run with sudo on macOS gets "Operation not permitted" reading files under a user's ~/Desktop even though the mode bits allow it. What is blocking it, and how is it resolved?

level: seniorimportance: should knowfreq 52%

basics

~20 s

TCC — Transparency, Consent and Control — is blocking it. TCC gates access to protected user data by the identity of the responsible application, not by uid, so running as root does not help. The fix is granting Full Disk Access to the app that launched the script.

open as a page

On a managed Mac fleet, what is a configuration profile, and what can an MDM enforce through one that a shell script running as root on the same machine cannot?

level: seniorimportance: should knowfreq 46%

basics

~20 s

A configuration profile is a signed property-list document of typed payloads that macOS installs as managed policy. Since macOS 11 profiles cannot be installed from the command line — only by user approval or by an MDM — and some settings, notably privacy approvals and extension allowlists, are only honoured from a supervised, MDM-managed Mac.

open as a page

A macOS build machine shows mds_stores consuming CPU and hammering the disk whenever a build runs. What is that process doing, and how do you control it for specific volumes or directories?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

That is Spotlight's metadata indexer reacting to the thousands of files a build creates and deletes. Use mdutil to check status and disable indexing per volume (mdutil -i off), and keep individual directories out of the index by naming them with a .noindex suffix or adding them to the Spotlight privacy list.

open as a page

On macOS 11 and later, the startup disk holds a read-only System volume and a writable Data volume that nonetheless appear as one directory tree. What joins them, and how is the System volume protected from modification?

level: seniorimportance: nice to knowfreq 34%

basics

~20 s

The two volumes form an APFS volume group joined by firmlinks, which splice Data-volume directories such as /Users into the read-only System tree. The System volume is cryptographically sealed, and macOS boots from a read-only snapshot of it whose seal is verified.

open as a page

showing 1–30 of 35