if / else

var score = 85;

if (score >= 90) {
    Write("A");
} else if (score >= 80) {
    Write("B");
} else if (score >= 70) {
    Write("C");
} else {
    Write("F");
}

Omitting braces works for single statements but is not recommended:

if (valid) doSomething(); // works but fragile

Truthy / Falsy Checks

var value = Platform.Request.GetQueryStringParameter("id");

// Preferred: !! coercion or direct truthiness check
if (!value) {
    // value is "", null, undefined, 0, or false
    Platform.Response.Redirect("/error", false);
}

// Explicit empty string check
if (value === "" || value === null) {
    // strictly no value
}

SFMC functions often return "" (empty string) rather than null/undefined when data is missing. Use !value or value === "" accordingly.

Boolean Coercion Patterns

// Convert to boolean explicitly
var hasValue = !!value;
var isActive = !!subscriber.active;

// Short-circuit for defaults
var name = Platform.Request.GetQueryStringParameter("name") || "Subscriber";

// Safe property access (no optional chaining in SSJS)
var city = (person && person.address && person.address.city) || "Unknown";
Show test script
<script runat="server">
/*
 * Chapter: if / else
 * Proves:
 *   1. if/else-if/else.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var grade = "B", out = "";
if (grade === "A") out = "A"; else if (grade === "B") out = "B"; else out = "F";
assert("elseif", out, "B");
</script>

switch

The switch statement works but has a known SFMC engine bug:

The default case may not execute reliably. If none of the case values match and execution reaches default, the engine may skip it.

var status = "pending";

switch (status) {
    case "active":
        Write("Active");
        break;
    case "inactive":
        Write("Inactive");
        break;
    default:
        // ⚠️ This may NOT execute in SSJS
        Write("Unknown status");
}

Safe pattern: Replace default with an explicit final else:

// Safer approach — use if/else for the fallback
var output = "";
if (status === "active") {
    output = "Active";
} else if (status === "inactive") {
    output = "Inactive";
} else {
    output = "Unknown status"; // Always works
}
Write(output);

Or check explicitly before the switch:

var validStatuses = { active: true, inactive: true };
if (!validStatuses[status]) {
    Write("Unknown status");
} else {
    switch (status) {
        case "active":   Write("Active");   break;
        case "inactive": Write("Inactive"); break;
    }
}

Fall-through

Empty stacked case labels do not fall through reliably in SFMC SSJS. Matching the first empty label leaves the shared body unexecuted:

var level = "admin";
var access = "";
switch (level) {
    case "admin":        // matches here…
    case "superuser":    // …but the body below does NOT run for "admin"
        access = "Full access";
        break;
    case "user":
        access = "Limited access";
        break;
}
// access is still "" when level === "admin"
// access is "Full access" when level === "superuser"

Duplicate the body (or use if / a lookup map) instead of relying on empty-case fall-through. See also the related switch break-escape bug.

Show test script
<script runat="server">
/*
 * Chapter: switch
 * Proves:
 *   1. case + default + fall-through.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var status = "inactive", out = "";
switch (status) { case "active": out = "Active"; break; case "inactive": out = "Inactive"; break; default: out = "Unknown status"; }
assert("inactive", out, "Inactive");
var level = "admin", access = "";
switch (level) { case "admin": case "superuser": access = "Full access"; break; case "user": access = "Limited access"; break; }
assert("DEV empty-case fallthrough skips body for first label (spec: runs)", access === "" ? "empty" : access, "empty");
level = "superuser"; access = "";
switch (level) { case "admin": case "superuser": access = "Full access"; break; case "user": access = "Limited access"; break; }
assert("matching non-empty stacked case runs body", access, "Full access");
</script>

Ternary

The ternary operator condition ? thenValue : elseValue is fully supported:

var greeting = hour < 12 ? "Good morning" : "Good afternoon";
var label = count === 1 ? "item" : "items";
var cssClass = isActive ? "active" : "inactive";

Avoid deeply nested ternaries — they become unreadable quickly.

Show test script
<script runat="server">
/*
 * Chapter: Ternary
 * Proves:
 *   1. Ternary values.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var hour = 9; assert("morning", hour < 12 ? "Good morning" : "Good afternoon", "Good morning");
assert("items", 1 === 1 ? "item" : "items", "item");
</script>

Short-Circuit Evaluation

Use && and || for concise conditional execution:

// Execute only if condition is true
isDebug && Write("<pre>" + Platform.Function.Stringify(data) + "</pre>");

// Default value
var timeout = config.timeout || 30;

// Safe property access
var name = user && user.profile && user.profile.firstName;
Show test script
<script runat="server">
/*
 * Chapter: Short-Circuit
 * Proves:
 *   1. && || short-circuit.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var wrote = false; true && (wrote = true); assert("and true", wrote ? "true" : "false", "true");
wrote = false; false && (wrote = true); assert("and false", wrote ? "true" : "false", "false");
var config = {}; assert("or default", config.timeout || 30, 30);
var user = { profile: { firstName: "Ada" } };
assert("safe access", user && user.profile && user.profile.firstName, "Ada");
</script>

Throw / Early Return

Use throw or early returns to guard against invalid states:

function processSubscriber(sk) {
    if (!sk) {
        throw new Error("SubscriberKey is required");
    }

    // String() first — a Lookup result throws on a truthiness test when the field is empty
    var email = String(Platform.Function.Lookup("Subscribers", "Email", "SubscriberKey", sk));
    if (email === "" || email === "null") {
        return null; // early return — nothing to process
    }

    // ... rest of function
    return email;
}

try {
    var result = processSubscriber(sk);
    if (result) {
        Write(result);
    }
} catch (e) {
    Write("Error: " + e.message);
}
Show test script
<script runat="server">
/*
 * Chapter: Throw / Early Return
 * Proves:
 *   1. throw Error (call-form) catchable; early return null.
 * EXPECTED OUTPUT: every line starts with PASS.
 */
function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
    var threw = false, msg = "";
    try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
    Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
function processSubscriber(sk) {
    if (!sk) { throw Error("SubscriberKey is required"); }
    if (sk === "missing") { return null; }
    return "ok:" + sk;
}
var msg = "";
try { processSubscriber(""); } catch (e) { msg = "" + e.message; }
assert("throw msg", msg, "SubscriberKey is required");
assert("early null", processSubscriber("missing") === null ? "null" : "other", "null");
assert("ok path", processSubscriber("abc"), "ok:abc");
</script>