This might feel familiar

PHP can embed server-side code in HTML. Cow uses a similar approach, but the code inside a Cow page is JavaScript or TypeScript. See the PHP introduction for PHP’s model.
PHP
<?php $name = 'herd'; ?>
<h1>Hello, <?= htmlspecialchars($name) ?>!</h1>
Cow
<?js const name = 'herd' ?>
<h1>Hello, <?= name ?>!</h1>
Both examples produce HTML for the browser. Cow's <?= ?> escapes text for HTML output, so it needs no htmlspecialchars(). To print HTML that your code built, use raw(). HTML escaping does not make a value safe inside JavaScript, CSS, or URLs.

What stays the same

  • The file is the URL. about.cow answers /about.
  • Every request starts fresh. A variable that you set in one request is gone in the next, as in PHP.
  • null prints nothing. <?= title; ?> works with the trailing semicolon.
  • A // comment ends at ?>. The final ?> in a file is optional.
  • Edit a page, refresh the browser, and see the change. No build step.

PHP to Cow

Find the PHP that you know on the left. The Cow equivalent is on the right.
In PHPIn CowGuide
<?php ... ?><?js ... ?> or <?ts ... ?>Language
<?= htmlspecialchars($name) ?><?= name ?> (escapes automatically)Language
<?= $html ?><?= raw(html) ?>Language
$_GET['name']req.get('name')API reference
$_POST and $_FILESawait req.formData()Forms & uploads
$_SERVER['REQUEST_METHOD']req.method()API reference
include 'header.php';await include('./_header.cow', { title })Modules & includes
require 'functions.php';import { greet } from './_functions.cow'Modules & includes
header('Location: /thanks');res.redirect('/thanks')Responses & files
http_response_code(404);res.status(404)API reference
echo json_encode($data);res.json(data)Responses & files
session_start(); and $_SESSIONawait session(db, req, res), then visitor.dataCookies & sessions
setcookie() and $_COOKIEsetCookie(res, ...) and cookies(req)Cookies & sessions
password_hash() and password_verify()hashPassword() and verifyPassword()Cookies & sessions
PDO with prepared statementsdb.all(sql, [values]) from cow:sqliteSQLite
phpinfo();cow.info()Errors & debugging
php -S 127.0.0.1:8000cow siteGet started
php -l page.phpcow check siteErrors & debugging

What changes

Use const, let, JavaScript objects, async/await, and JavaScript imports. Use <?ts when you want TypeScript syntax.
<?= ?> escapes what it prints, where PHP prints it unchanged. Wrap HTML that your code built in raw().
Cow supplies its own request, response, session, and database APIs. It does not run PHP code or PHP packages. npm support is subject to Cow’s compatibility limits.
Serve a directory with cow site. Cow provides the web server and maps page files to URLs.
A few differences can surprise you:
  • An include does not see the variables of the page that calls it. Pass values as the second argument, and read them from locals. include() is asynchronous, so await it.
  • There are no superglobals. Pages receive req, res, and cow. To use them in an imported helper, pass them as arguments.
  • Cow keeps the line break after a closing ?>, where PHP removes it. Browsers ignore the extra blank line in HTML.
  • echo('a', 'b') joins its values with a space. PHP's echo 'a', 'b'; does not.
  • To keep a file private, start its name with an underscore, such as _db.cow. Cow never serves it, so you do not need a folder outside the web root.