http://coldfusion.com logo
Join Slack
Powered by
# wheels-dev
  • r

    risto

    05/28/2026, 8:34 PM
    Okay trying the wheels cli in the shell. I do wheels --version and see the output with the ASCII art. I do wheels new blog and get
    Copy code
    wheels new blog
    [ERROR] Error: Unknown command, file, or module: 'new'
      - If it's a file, check the path and extension (.cfm, .cfs, .lucli)
      - If it's a module, run 'lucli modules list' to see available modules
      - Run 'lucli --help' to see available commands
    wheels --version
    Wheels Version: 4.0.1 (stable)
    
     __        ___               _
     \ \      / / |__   ___  ___| |___
      \ \ /\ / /| '_ \ / _ \/ _ \ / __|
       \ V  V / | | | |  __/  __/ \__ \
        \_/\_/  |_| |_|\___\___|_|___/
    
    <https://wheels.dev>
  • p

    Peter Amiri

    05/28/2026, 8:36 PM
    Are you on window, Mac, or Linux
    r
    • 2
    • 26
  • g

    Gareth

    06/02/2026, 10:41 PM
    hi
    z
    • 2
    • 1
  • p

    Peter Amiri

    06/03/2026, 3:09 AM
    Hi Gareth, welcome to the channel
  • a

    angel

    06/03/2026, 5:23 PM
    I'm migrating from CFWheels 2.5 to Wheels 3. Having an issue with model properties being lowercase, so a property of
    isHidden
    is returned as
    ishidden
    which breaks the consumer of the API (yes, I read the docs, not recommended to use Wheels for APIs). The only way to fix it that I've found is to create properties on the model via the
    property()
    function. I've tried using
    returnAs="structs"
    and
    returnAs="struct"
    which according to the documentation, should preserve case but it does not. Using
    renderText()
    does not work since the properties are all lower case coming out of the model. Is there a way to get the casing working like in CFWheels 2.5 via a configuration? I want to avoid modifying as much as the code as possible, thanks!
    z
    p
    • 3
    • 34
  • a

    Adam Brunt

    06/08/2026, 9:33 AM
    We are still on v1.4.5 and I had a question about Wheels handles transactions, and locks, under the hood. For example https://api.wheels.dev/v1-4-5/miscellaneous/update/ says the
    transaction
    argument is required but we have never supplied it - I am assuming it defaults to
    commit
    ?? But what I am really interested in is how long Wheels waits (if it does) for a lock to be released if some other process is updating the same model row that it is trying to update? In particular, is there functionality in Wheels to automatically handle scenarios when model/adapters/Base.cfc throws errors such as "Deadlock found when trying to get lock; try restarting transaction" ?
    z
    p
    • 3
    • 6
  • p

    Peter Amiri

    06/10/2026, 12:21 PM
    Wheels 4.0.3 is out πŸŽ‰ (third patch on the 4.0 line β€” no breaking API changes) The theme this time is a CLI you can trust in scripts. LuCLI hands the CLI structured arguments, but the command layer flattened them back to argv and re-parsed by hand β€” and that round trip silently dropped
    --no-*
    negations and every named-only invocation.
    wheels seed --environment=production
    quietly seeded development. All 24 commands now parse through one typed
    ArgSpec
    , and the lossy shim is gone. Highlights: β€’
    --no-sqlite
    /
    --no-routes
    /
    --no-test-db
    and named-only flags now actually work everywhere β€’ CLI failures exit non-zero β€” a typo'd subcommand or failed migration no longer looks green to CI β€’
    wheels migrate
    /
    seed
    /
    reload
    /
    g admin
    refuse to attach to a different project's server (the wrong-database footgun) β€’ PostgreSQL/CockroachDB FK migrations work again (
    --belongsTo
    scaffolds crashed before), and Oracle 19c/21c
    DROP TABLE
    is fixed β€’ Framework helpers like
    env()
    can no longer be invoked as controller actions from a URL β€’
    wheels new
    keeps generated secrets in
    .env
    , not in committed config Upgrade:
    brew upgrade wheels
    /
    scoop update wheels
    /
    apt upgrade wheels
    /
    dnf upgrade wheels
    Full write-up: https://blog.wheels.dev/posts/wheels-4-0-3-released
  • r

    risto

    06/12/2026, 6:05 PM
    When I do install wheels-core in commandbox it installs it to /mydirectory/vendor/wheels/vendor/wheels/ is that correct?
    p
    • 2
    • 5
  • p

    Peter Amiri

    06/16/2026, 4:22 PM
    New on the blog: Migrations That Survive a Team β€” the Wheels 4.0 Migrator. <Full Post> A broad how-to on writing migrations that hold up on someone else's checkout against a shared dev database: β€’
    createTable
    returns a builder β€” nothing runs until you call
    .create()
    (or
    .change()
    for
    changeTable
    ). The #1 silent footgun. β€’ The column helpers all speak
    columnNames
    (plural, comma-list to add several at once).
    primaryKey()
    is the one exception β€” it does NOT split on commas. β€’
    timestamps()
    adds THREE columns: createdAt, updatedAt, AND deletedAt (the soft-delete marker). Don't hand-roll them. β€’
    execute()
    takes only
    sql
    β€” no parameter binding. Inline SQL +
    NOW()
    for portable dates; `addRecord()`/`updateRecord()` when you need binding. β€’ Each migration runs in its own transaction; a failure stops the loop and leaves you consistent. β€’ The team part:
    migrate info
    flags orphan rows
    [?]
    ,
    migrate doctor
    gives a health report, and `forget`/`pretend --yes` reconcile a shared DB without rolling back the wrong way. Shared-DB reconciliation has its own deep dive in the 4.0.2 release notes β€” this post is the get-started-and-stay-out-of-trouble version.
  • p

    Peter Amiri

    06/17/2026, 4:18 AM
    New on the blog: Wheels + Claude: Building a Feature via the stdio MCP πŸ”§ There are two ways to make an AI assistant useful inside a framework. The lazy one is a chat sidecar that generates snippets you paste. The good one is teaching the assistant the framework's own vocabulary -- and that's what Wheels 4.0 ships. The model doesn't write code; it decides which CLI command to run, and the framework generates everything exactly the way it always has. The whole MCP server is just
    cli/lucli/Module.cfc
    -- its public functions become tools by reflection. No port, no socket, no running dev server. The AI editor spawns
    wheels mcp wheels
    and speaks JSON-RPC 2.0 over stdio. What the post covers: β€’ The reflection model: the CLI is the MCP server -- no second surface to drift β€’ Setup with one
    .mcp.json
    snippet (no
    wheels mcp setup
    -- that command doesn't exist;
    wheels mcp
    just prints the config and writes nothing) β€’ The 18-tool surface and exactly why
    console
    , `start`/`stop`,
    new
    , and friends are excluded β€’ A worked example: shipping a commenting feature end-to-end through Claude Code -- generate, migrate, test β€’ The deprecated
    /wheels/mcp
    HTTP endpoint and why stdio replaced it β€’ A bit of template drift we found while writing the post (the OpenCode template still pointed at the old HTTP endpoint with a literal
    {PORT}
    ) The tools advertise bare names --
    generate
    ,
    migrate
    ,
    test
    ,
    destroy
    . Clients namespace them under the server, so Claude Code shows them as
    mcp__wheels__generate
    . <https://blog.wheels.dev/posts/wheels-claude-stdio-mcp>
  • z

    Zain Ul Abideen

    06/19/2026, 11:05 AM
    πŸš€ Community Feedback Request: Legacy Wheels Migration Tool I’m currently developing a migration tool aimed at helping teams upgrade legacy
    Wheels
    applications (1.x, 2.x, and 3.x) to newer versions with less manual effort and reduced risk. To make sure the tool solves
    real-world
    problems, I’d love feedback from developers and organizations currently maintaining older Wheels applications. As a thank you, anyone who participates and provides detailed feedback will receive free access to the migration tool once it’s ready. A few questions: 1. What version of Wheels are you currently running? 2. How old is your application? 3. What ColdFusion/Lucee version are you using? 4. Have you ever attempted a Wheels upgrade? If yes, what challenges did you encounter? 5. What are the biggest concerns preventing an upgrade today? β€’ Breaking changes β€’ Lack of time/resources β€’ Third-party plugins β€’ Legacy code complexity β€’ Lack of testing β€’ Deployment risk β€’ Other 6. Approximately how large is your application? β€’ Number of models β€’ Number of controllers β€’ Estimated LOC (if known) 7. Do you have automated tests in place? 8. Are you using Docker, CI/CD, or other deployment automation? 9. Which migration tasks would you most like to automate? 10. If a migration tool could solve one major pain point for your team, what would it be? My goal is to build tooling that helps identify upgrade blockers, automate repetitive migration tasks, and provide a safer upgrade path for legacy Wheels applications. Your feedback will directly influence the roadmap and features of the migration tool. Thank you for helping make legacy Wheels upgrades easier for the entire community!
  • p

    Peter Amiri

    06/19/2026, 1:55 PM
    New release on the blog: Wheels 4.0.5 β€” a hardening release, now installable anywhere. <https://blog.wheels.dev/posts/wheels-4-0-5-released | Read the Announcement> 4.0.4 was a big one (100+ commits) and 4.0.5 makes it installable everywhere β€” same day, so this one post covers both: β€’ Security β€” open-redirect hardening,
    /wheels/info
    no longer leaking
    csrfCookieEncryptionSecretKey
    or datasource creds, fail-closed dev-UI + reload gates, a new
    trustProxyHeaders
    setting. β€’ Performance β€” lock-free `model()`/`controller()` warm path, memoized route lookups, schema-column cache, O(1) dispatch gate. β€’
    wheels deploy
    grew up β€” ~20 Kamal-port fixes: fresh-host boot, all-or-nothing fleet lock, secret redaction, audit trail. β€’ Cross-engine β€” Adobe CF reload 500s on case-sensitive filesystems fixed, BoxLang null hardening, Oracle/SQL Server identity retrieval. β€’ Install it anywhere β€” `brew`/`scoop`/`apt`/`dnf`, now including arm64 Linux, install-tested daily. If you grabbed 4.0.4: just upgrade to 4.0.5. Everything in 4.0.4 is in it.
  • p

    Peter Amiri

    06/22/2026, 3:15 PM
    New on the blog: Beyond findAll β€” Scopes, Enums, and the Chainable Query Builder. <https://blog.wheels.dev/posts/beyond-findall-scopes-enums-query-builder | Full Post> What it covers: β€’ Scopes β€” named, reusable query fragments. Static (literal where/order) and dynamic (handler returns a spec struct with whereParams). β€’ Enums β€” one
    enum(property="status", values="draft,published,archived")
    registers a validation, three boolean checkers (isDraft, isPublished, isArchived), and three scopes (.draft(), .published(), .archived()). All parameterised. β€’ The chainable query builder β€” .where("col", value), .whereIn, .whereBetween, .orderBy, .limit, .get(). Auto-quoting + type validation on the way to SQL, so integer/float/boolean payloads can't sneak past the binding layer. β€’ Three features, one design β€” they all return deferred-query proxies that materialise into the same finder-argument struct on a terminal call. The chain reads top-to-bottom in the order you'd describe the query out loud. Side effect of writing the post: framework fix (#2736) β€” whereIn / whereNotIn with empty arrays no longer emit malformed
    IN ()
    SQL. whereIn(empty) now sets a flag the terminals honour (count β†’ 0, exists β†’ false, findAll β†’ empty query, etc.); whereNotIn(empty) is a no-op (exclude-none = match-all). Same user-facing behaviour as Rails / Sequel / Django / Eloquent. Fourteen regression specs locked in.
  • p

    Peter Amiri

    06/23/2026, 8:35 PM
    New on the blog: Real-Time Without WebSockets β€” Server-Sent Events in Wheels 4.0. <https://blog.wheels.dev/posts/server-sent-events-wheels-4> Most "real-time" features are one-directional β€” the server has news, the client wants to hear it. You don't need WebSockets for that. You need a pipe that pushes, and Wheels 4.0 ships SSE as first-class controller helpers. What it covers: β€’
    renderSSE(data=..., event=..., retry=...)
    β€” one event per request, browser auto-reconnects. Spec-covered, engine-safe, holds no thread. The one to reach for. β€’ The streaming trio β€”
    initSSEStream()
    returns the raw writer, then
    sendSSEEvent
    /
    sendSSEComment
    (keep-alive heartbeat) /
    closeSSEStream
    for long-lived pushes. β€’
    isSSERequest()
    β€” serve SSE to EventSource clients and HTML to everyone else from one action. β€’ The bounded streaming loop β€” timeout cap,
    writer.checkError()
    disconnect detection, heartbeats,
    sleep
    , try/finally close. CFML holds a worker thread for the whole connection, so this part is mandatory. β€’ The one real sharp edge:
    initSSEStream()
    is engine-fragile on BoxLang and not spec-covered end-to-end. Hand-test streaming per engine;
    renderSSE
    has no such caveat. About 4 lines of controller code for server-to-client updates, no second protocol.
  • p

    Peter Amiri

    06/26/2026, 5:27 AM
    New on the blog: Writing Your Own Middleware in Wheels 4.0. <blog.wheels.dev/posts/writing-custom-middleware-wheels-4|Full Post> The rate-limiting post covered using the built-in middleware. This one is the other half β€” authoring your own. It's a small surface that hides one lifecycle decision that will bite you if you miss it. What it covers: β€’ The one-method contract β€”
    handle(request, next)
    returns a string; code before
    next()
    runs in, code after runs out. β€’ Why
    request
    is NOT the CFML
    request
    scope (it's a
    {params, route, pathInfo, method}
    struct) and the Adobe CF scope-shadow trap that follows. β€’ The lifecycle that changes everything: every middleware is a singleton shared across all concurrent requests for the app's lifetime β€” so any mutable state MUST be locked. Worked example with a
    cflock
    -guarded counter. β€’ Short-circuiting β€” return a string WITHOUT calling
    next()
    to skip the controller (how RateLimiter does its 429 and Cors does OPTIONS). β€’ Registration: global in config/settings.cfm vs route-scoped in config/routes.cfm, string-path vs object-instance, and why global always runs before route-scoped. Three worked components: a request timer, a thread-safe audit logger, and a maintenance gate.
  • p

    Peter Amiri

    06/26/2026, 5:51 PM
    New on the blog: Dependency Injection in Wheels 4.0 β€” services.cfm, scopes, and auto-wiring. <https://blog.wheels.dev/posts/dependency-injection-services-scopes/> What it covers: β€’ Registering services in
    config/services.cfm
    with
    injector()
    + the fluent
    di.map("x").to("...").asSingleton()
    chain (and yes β€” you create that file yourself; the scaffold ships none) β€’ The three lifetimes β€” transient (the DEFAULT, the one that bites),
    .asSingleton()
    ,
    .asRequestScoped()
    β€” and when to reach for each β€’ Resolving anywhere with
    service("name")
    (it throws
    Wheels.DI.ServiceNotFound
    , it doesn't return null) β€’ Controller
    inject("a, b")
    in config() β†’ use as
    this.a
    in actions, resolved per-request β€’ Constructor auto-wiring:
    init()
    param names that match registered mappings get filled in for free β€’ Sharp edges: singletons cached by mapping NAME not component path; auto-wiring only fires with empty initArguments;
    mapInstance()
    vs
    map()
    in plugins A user-facing how-to β€” not the wheelsdi internals story (that's the earlier "From WireBox to wheelsdi" post).
  • p

    Peter Amiri

    06/30/2026, 1:19 AM
    New on the blog: Seeding Your Database the Idempotent Way. <https://blog.wheels.dev/posts/idempotent-database-seeding/> What it covers: β€’
    seedOnce()
    β€” the idempotent seed helper. Create a row only if a matching one doesn't already exist; safe to run a hundred times. β€’ The file convention:
    app/db/seeds.cfm
    (runs in every environment) then
    app/db/seeds/<env>.cfm
    (env-specific, sibling directory β€” NOT a hyphenated suffix). β€’ Why the whole run is one transaction that rolls back on ANY validation failure (#2973) β€” a half-applied seed run must never look fully-applied. β€’ Composite uniqueness, seeding from code via
    application.wheels.seeder
    , and the CLI:
    wheels seed
    , scaffold with
    wheels generate snippets seed-data
    . β€’ Sharp edges: it's a skip not an upsert,
    --generate
    is random non-idempotent junk, and
    wheels db:seed
    /
    wheels generate seed
    are not real commands.
  • p

    Peter Amiri

    07/01/2026, 12:05 PM
    New on the blog: Routing Deep-Dive β€” Resources, Nested Callbacks, and Route Model Binding. <https://blog.wheels.dev/posts/routing-resources-model-binding/> What it covers: β€’
    resources()
    β†’ the 7 RESTful routes from one call (and why
    update
    is secretly TWO routes β€” PATCH and PUT) β€’ Nested resources: the callback form auto-closes for you;
    nested=true
    makes YOU call
    .end()
    . Mix them and you add an extra end() that pops an empty scope stack and throws. β€’ Route model binding β€”
    binding=true
    resolves
    <http://params.post|params.post>
    before your action runs and 404s a missing record, so the findByKey + not-found dance disappears β€’ Convention vs explicit binding diverge on a missing model class (skip vs re-throw); a missing record always 404s β€’ The traps: route order is load-bearing (wildcard LAST), and you can't name an action after a framework helper (
    model
    ,
    redirectTo
    , the
    is*
    predicates) or it 404s Standalone how-to with a full worked
    config/routes.cfm
    . If you've ever shipped
    /posts/999999
    and gotten a stack trace instead of a 404, this is the post.
  • p

    Peter Amiri

    07/03/2026, 5:15 AM
    New on the blog: Validations Beyond Presence β€” conditional rules, custom validators, and enum integration in Wheels 4.0. <https://blog.wheels.dev/posts/validations-conditional-enum/ > What it covers: β€’ The full validator surface in one worked model β€” presence, scoped uniqueness, format, length, numericality, inclusion/exclusion, confirmation β€’ Conditional validation with
    condition
    /
    unless
    /
    when
    β€” and why those are a fixed-grammar string parser, NOT
    Evaluate()
    (bad expressions silently skip in production) β€’ Custom
    validate()
    /
    validateOnCreate()
    /
    validateOnUpdate()
    β€” register a method name, fail by calling
    addError()
    (the return value is ignored β€” the #1 gotcha) β€’
    enum()
    β€” one call that auto-registers
    validatesInclusionOf
    , generates
    isDraft()
    -style checkers, and creates per-value scopes β€’ Reading errors right:
    errorsOn()
    returns an array of
    {property, message, name}
    STRUCTS β€” loop and read
    .message
    , don’t print the struct Plus a β€œsharp edges” section: scoped uniqueness isn’t a DB constraint, presence is skipped on columns with a DB default, confirmation errors land on the virtual
    passwordConfirmation
    property, and
    allowBlank
    defaults to false everywhere.
  • p

    Peter Amiri

    07/03/2026, 5:15 AM
    New on the blog: Form Helpers in Wheels 4.0 β€” Object Forms, HTML5 Fields, and Error Rendering. <https://blog.wheels.dev/posts/form-helpers-objects-and-html5/ > What it covers: β€’ The one mental model β€”
    objectName
    is the variable name (a string), not the object.
    textField(objectName="user", property="email")
    emits
    name="user[email]"
    and round-trips into
    params.user.email
    . β€’ The real HTML5 single-input roster β€” emailField, urlField, numberField, telField, dateField, colorField, rangeField, searchField (+ textField with a type override). No timeField/dateTimeField/monthField/weekField exist. β€’
    method="put"
    isn't real HTTP β€” startFormTag rewrites to POST + a hidden
    _method
    field, and auto-appends the CSRF token for non-GET. β€’ The unchecked-checkbox problem and how
    uncheckedValue
    (on by default, with the
    ($checkbox)
    companion) keeps the param from vanishing. β€’
    *Tag
    helpers (flat params, for search/login/filters) vs object helpers (nested params). β€’ errorMessagesFor (a
    <ul>
    of everything) vs errorMessageOn (first message, inline). β€’ There's no standalone label() helper β€” labels come from the
    label=
    arg, and the input nests inside the label by default. A worked, end-to-end create/edit form, plus a Sharp Edges section built from the behaviors that bite first.
  • p

    Peter Amiri

    07/04/2026, 5:15 PM
    New on the blog: Associations Deep-Dive β€” hasMany, belongsTo, Nested Properties, and Eager Loading. <https://blog.wheels.dev/posts/associations-deep-dive-wheels-4/ > What it covers: β€’ The three association types (belongsTo / hasMany / hasOne), how Wheels deduces modelName + foreignKey + joinKey from one
    name
    arg, and when to override them β€’ The exact dynamic methods each one generates β€”
    author.posts()
    ,
    author.postCount()
    ,
    author.addPost()
    ,
    author.deleteAllPosts()
    , and the rest β€” with a table per type β€’
    dependent=
    and its five legal values (delete / deleteAll / remove / removeAll / false). There is NO `nullify`; FK-nulling is
    remove
    /
    removeAll
    .
    belongsTo
    has no
    dependent
    at all. β€’
    nestedProperties
    β€” save a parent and its children from one form submit;
    autoSave
    defaults true,
    allowDelete
    defaults false β€’ Eager loading with
    include=
    to kill the N+1, why nested
    include="artist(genre)"
    is query-only, has-many-through via
    shortcut
    , and why a polymorphic belongsTo can't be eager-loaded Plus a Sharp Edges section: getters return QUERIES not arrays, join-type defaults differ by association (belongsTo inner-joins and silently drops parentless rows), and mixed positional+named args error every time.
    πŸ™Œ 1
  • p

    Peter Amiri

    07/06/2026, 3:02 PM
    New on the blog: Caching in Wheels 4.0 β€” Actions, Queries, Partials, and Invalidation. <https://blog.wheels.dev/posts/caching-in-wheels-4/> What it covers: β€’ Why your
    cache=
    args do nothing on your laptop β€” caching is OFF in development by default (cacheActions/cachePages/cachePartials/cacheQueries all false in dev) β€’ Action caching with
    caches()
    , including
    static=true
    (whole page via cfcache, aborts before filters) and
    appendToKey
    to vary by user β€’ The TWO query caches everyone confuses β€” request-level dedupe (always on) vs
    findAll(cache=N)
    engine caching β€” and why
    reload=true
    only defeats one of them β€’ Partial + page caching via
    includePartial(cache=...)
    /
    renderView(cache=...)
    β€’ The uncomfortable truth about invalidation: there's no
    clearCache(key)
    .
    clearCachableActions()
    only unregisters; real eviction = short times +
    ?reload=true
    β€’ Sharp edges: cache times are MINUTES not seconds, the 5000-item bounded cache silently drops new entries when full, static caching no-ops on engines without cfcache A worked blog-home-page example ties it together β€” action cache as the outer skin, query + partial caches underneath.
  • p

    Peter Amiri

    07/07/2026, 5:59 PM
    New on the blog: File Uploads in Wheels 4.0, the Idiomatic Way. <https://blog.wheels.dev/posts/file-uploads-in-wheels-4/ > Wheels 4.0 has no ActiveStorage-style attachment system β€” no
    hasAttachment
    , no upload service, no
    params.file
    . And that's fine. The honest idiomatic flow is five steps, and this post walks every one end to end. What it covers: β€’ The multipart trap β€”
    startFormTag
    does NOT auto-add
    enctype
    just because a
    fileField
    is on the form. Default is
    multipart=false
    . Forget
    multipart=true
    and the upload fails silently β€” no error, file posts as plain text. This eats more uploads than everything else combined. β€’
    fileField
    vs
    fileFieldTag
    β€” bound (
    user[avatar]
    ) vs unbound (
    document
    ) field names, and why the name is your contract with the controller. β€’ The controller β€” native CFML
    cffile action="upload"
    (Wheels has zero upload wrapper),
    nameConflict="makeUnique"
    , and copying the result onto
    params.user
    so the model can validate it. β€’ Validation β€”
    validatesFormatOf
    over the stored string + a custom
    validate()
    callback for size/MIME, because validators can't see multipart uploads. β€’
    sendFile
    β€” the one direction with a real Wheels helper, with built-in path-traversal protection. Plus a "Sharp edges" section of real, source-confirmed gotchas.
  • p

    Peter Amiri

    07/09/2026, 1:21 AM
    New on the blog: Sending Email in Wheels 4.0 β€” sendEmail, Templates, and Background Delivery. <https://blog.wheels.dev/posts/sending-email-in-wheels-4/ > What it covers: β€’
    sendEmail
    is the whole mailer β€” no Mailer class, no ActionMailer. One controller helper that renders a view and sends it. β€’ The arg-routing rule: a
    cfmail
    attribute goes to the email, everything else becomes a view variable. Get the name wrong and your reply-to silently becomes template data. β€’ Email template resolution β€” bare name vs. leading-slash, and why the slash matters. β€’ Multipart text+html and the
    <
    -counting heuristic that flips your parts if your text body has code in it.
    detectMultipart=false
    fixes it. β€’ Attachments, and
    deliver=false
    as the preview/test path. β€’ The big one: the bare
    sendEmail()
    inside a Job's
    perform()
    that the docs show does not work β€” a Job is a plain component with no controller mixins. The fix is
    controller("Mailer").sendEmail(...)
    . Full background-delivery example included.
  • r

    risto

    07/14/2026, 2:19 AM
    Been using cfwheels since v1 reload in the browser and never not worked. Using v4 latest and just have set(reloadPassword=""); in settings but does not reload with ?reload=true. I always have to restart. Any ideas I can try?
    z
    p
    • 3
    • 14
  • g

    gknight

    07/17/2026, 12:32 AM
    @gknight has left the channel
  • p

    Peter Amiri

    07/22/2026, 12:01 PM
    New on the blog: wheels console β€” The Debugging Move You're Not Using. <https://blog.wheels.dev/posts/wheels-console-debugging/> The rails-console move, for Wheels: a REPL evaluated INSIDE your running dev app. Models resolve, scopes chain, service() answers, get() reads the real merged config. What it covers: - The three-line validation session that replaces form-submit-dump archaeology: new() -> valid() -> errorsOn() - Scope-chain verification before you touch a view; DI resolution checks before the 500 three requests later - The slash-commands: /models, /routes (which pattern wins, from the dispatcher's own data), /env, /reload - console vs repl β€” same look, different tools: full app context + running server vs bare CFML calculator - Two habits: verify state after migrations/seeds instead of trusting memory, and respect that deleteAll() at the prompt is real - The honest boundary: dev-workflow tool; production questions belong to observability, not a REPL on a prod box
  • p

    Peter Amiri

    08/21/2026, 2:31 PM
    Wheels 4.0.6 is out. First 4.0 release that’s about what you can build:
    wheels generate auth
    , an authorization policy layer, pluggable storage disks, and a query builder that finally lets
    select()
    start a chain. Also lands the mixin-plan cache that was making 4.0.x feel slower than 2.x. Write-up: blog.wheels.dev/posts/wheels-4-0-6-released Discussion: github.com/wheels-dev/wheels/discussions/3390
    Copy code
    brew upgrade wheels
    # or scoop / apt / dnf
    wheels --version   # Wheels Version: 4.0.6
    βœ… 1
  • p

    Peter Amiri

    09/28/2026, 6:22 PM
    πŸš€ Wheels 4.1.1 is out A point release with a CLI security fix and the 4.1.0 papercuts: β€’ πŸ”’ Security (GHSA-x3cm-2j3q-jgg4, medium): the CLI now only talks to your project's own verified server for state-changing commands, and the reload password moved from the URL to a header β€’ βœ… Adobe CF 2023/2025: no more HTTP 500 on the first request after a restart β€’ πŸ—ƒοΈ Multi-database migrations no longer stall β€’ πŸ”§ Oracle / SQL Server / H2 fixes, pagination,
    offset()
    , stricter CLI arguments,
    wheels test
    exit codes Upgrade:
    brew upgrade wheels
    (or scoop/apt/dnf), then
    wheels upgrade apply
    . Copy the reload-password header block into your `public/Application.cfc`; details in the post. πŸ“ blog.wheels.dev/blog/wheels-4-1-1-released _apt users: if
    wheels
    fails with
    UnsupportedClassVersionError
    , run
    unset JAVA_HOME
    (it needs Java 21). The fix is in 4.1.2._
  • r

    Rodney

    09/28/2026, 6:54 PM
    @Rodney has left the channel