# How to create a PAC file: by hand, from an example, or with the generator

Source: https://findproxyforurl.net/articles/how-to-create-a-pac-file/ · updated 2026-10-11

Changed 2026-10-11: The page now says correctly that Windows runs let, const and arrow functions but fails on newer syntax such as ?. and ??, and links the new article on PAC files on Windows.

A PAC file is a text file with one JavaScript function in it. You can write it in any text editor in a few minutes. This article builds one from nothing, block by block, then shows the mistakes that cause the most trouble and the faster ways to get a good file.

## A PAC file is one function that answers one question

For every request, the browser calls the function `FindProxyForURL(url, host)` in the PAC file and
asks: "which proxy should I use for this request?". `url` is the full address of the request, and
`host` is only the host name from it, such as `www.example.com`. The function answers with a text
string:

- `"DIRECT"` means: connect without a proxy.
- `"PROXY proxy1.corp.example:8080"` means: use this proxy.
- `"PROXY proxy1.corp.example:8080; PROXY proxy2.corp.example:8080"` is a list. The browser tries the
  entries from left to right and takes the next one when a proxy does not answer.

That is the whole interface. The [FindProxyForURL reference](https://findproxyforurl.net/findproxyforurl/) has the details,
and the [function reference](https://findproxyforurl.net/functions/) lists the helper functions, such as
[`dnsDomainIs()`](https://findproxyforurl.net/functions/dnsdomainis/) and [`isPlainHostName()`](https://findproxyforurl.net/functions/isplainhostname/),
that every PAC engine provides.

## Start with the default route

Open a plain-text editor, create a file named `proxy.pac`, and write the line that decides every
request first:

```js
function FindProxyForURL(url, host) {
  // Default route: everything goes through the corporate proxies
  return "PROXY proxy1.corp.example:8080; PROXY proxy2.corp.example:8080";
}
```

This is already a working PAC file. Everything you add from now on goes *above* this `return`,
because the first `return` that runs decides the request, and the default route must stay the last
statement. If the function can end without a `return`, browsers connect directly and the traffic
silently bypasses the proxy ([details](https://findproxyforurl.net/rules/no-default-return/)).

## Lower-case the host before you compare it

```js
  host = host.toLowerCase();
```

This goes in as the first line of the function. Host names are not case-sensitive, but the
comparisons in your file are, and not every client lower-cases the host before it calls the PAC
file ([details](https://findproxyforurl.net/rules/host-not-lowercased/)).

## Send internal destinations direct

Add one `if` block per group of destinations, each ending in a `return`:

```js
  // plain host names (no dot) are on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // the internal DNS zone and all its hosts
  if (host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }
```

Put the cheapest tests first. `isPlainHostName()` only checks whether the name contains a dot. For a
domain, you need both tests: `dnsDomainIs()` with the leading dot matches every host inside the
zone, and `==` matches the zone name itself.

Internal networks need care, because the obvious test `isInNet(host, "10.0.0.0", "255.0.0.0")`
makes the browser look the name up in DNS for every request. Test networks only when the URL
contains an IP address, as the [local bypass example](https://findproxyforurl.net/examples/#local-bypass) does.

## The complete first file

Put the pieces together and you have a file that most company networks can start with:

```js
function FindProxyForURL(url, host) {
  host = host.toLowerCase();

  // plain host names (no dot) are on the local network
  if (isPlainHostName(host)) {
    return "DIRECT";
  }

  // the internal DNS zone and all its hosts
  if (host == "corp.example" || dnsDomainIs(host, ".corp.example")) {
    return "DIRECT";
  }

  // Default route: everything else goes through the corporate proxies
  return "PROXY proxy1.corp.example:8080; PROXY proxy2.corp.example:8080";
}
```

Replace `corp.example` and the proxy names with your own, then test the file in the
[PAC file checker](https://findproxyforurl.net/check/) with the URLs that matter to you.

## The mistakes that hurt most

Most broken PAC files fail in one of a few ways. The [20 most dangerous PAC mistakes](https://findproxyforurl.net/top-20/)
lists all of them; these five come up most often in new files:

1. **Testing the host pattern against `url` instead of `host`.** `url` contains the scheme, path
   and query, so a host pattern either never matches or matches far too much
   ([details](https://findproxyforurl.net/rules/url-instead-of-host/)).
2. **`dnsDomainIs()` without the leading dot.** `dnsDomainIs(host, "corp.example")` also matches
   `notcorp.example` ([details](https://findproxyforurl.net/rules/dnsdomainis-without-leading-dot/)).
3. **DNS lookups in the file.** `dnsResolve()`, `isResolvable()` and `isInNet()` on a host name each
   cost a DNS lookup before the page starts to load ([details](https://findproxyforurl.net/rules/dns-function-on-hot-path/)).
4. **Modern JavaScript.** Newer syntax works in browsers, but some clients run the file with an
   older JavaScript engine. pactester before version 1.5 rejects `let` and `const`, and Windows
   rejects newer syntax such as `?.` and `??`. For them the whole file is a syntax error
   ([details](https://findproxyforurl.net/rules/es2015-syntax/), [PAC files on Windows](https://findproxyforurl.net/articles/pac-on-windows/)).
5. **No `return` at the end.** As described above, a missing default route sends traffic past the
   proxy without any error ([details](https://findproxyforurl.net/rules/no-default-return/)).

The checker finds all five and explains each finding with the line it is on.

## The faster ways: an example or the generator

You do not have to start from an empty file:

- The [PAC file examples](https://findproxyforurl.net/examples/) are complete files for common cases: one proxy for everything,
  local traffic direct, a different proxy per domain, failover, SOCKS, one file per site, and the
  files for the common cloud proxy services. Each one scores A+ in the checker.
- The [annotated reference proxy.pac](https://findproxyforurl.net/examples/reference/) explains a production file block by
  block.
- The [PAC file generator](https://findproxyforurl.net/generate/) builds a file from your own lists of proxies, hosts, domains
  and networks, with a comment next to every entry. The page also explains where to set the file's
  URL on Windows, macOS and in group policy.

When the file is ready, [test it](https://findproxyforurl.net/articles/how-to-test-a-pac-file/) and serve it with the content
type `application/x-ns-proxy-autoconfig`.


## Frequently asked questions

### How do I create a PAC file?

Create a text file named proxy.pac with a function FindProxyForURL(url, host) that returns "DIRECT" or "PROXY host:port" for each request. Start with the default route, add the destinations that go direct above it, test the file, and serve it from a web server with the content type application/x-ns-proxy-autoconfig.

### Which program do I need to write a PAC file?

Any plain-text editor. Save the file as plain ASCII without a byte order mark, and do not use a word processor, because it turns straight quotes into curly ones, which are a syntax error in JavaScript.

### What is the simplest possible PAC file?

A FindProxyForURL function with a single line, return "PROXY proxy.corp.example:8080";, which sends every request to one proxy. A real file adds direct routes for internal destinations and a second proxy for failover.

### Can I create a PAC file without writing code?

Yes. The PAC file generator on this site builds a commented file from your lists of proxies, hosts, domains and networks, and the examples page has complete files that you can copy and adapt.

### How do I test a new PAC file?

Open it in an online PAC file tester such as findproxyforurl.net/check/, trace the URLs that matter to you one by one, and check which proxy each one gets in the engine profiles your users run (Chromium, Firefox or pacparser). Then roll it out to a small pilot group before everyone gets it.

