Secondary Datasource Access in Vibe Code Blocks & more user properties

Currently, useRecord() and useCurrentRecordId() in a Vibe Code block are tightly coupled to the block’s single connected datasource. When a block is placed on a detail page, useCurrentRecordId() correctly returns the page record’s ID — but useRecord() queries the connected datasource, not the page record’s table.

Please allow Vibe Code blocks to read from a second datasource (or the current page record) independently of the block’s primary connected datasource.

Option A — Secondary datasource connection Allow a Vibe Code block to be connected to two datasources. The primary datasource drives useRecordCreate / useRecordUpdate. A secondary datasource exposes a read-only useContextRecord() hook scoped to the page record.

Option B — Expose page record fields directly Provide a useCurrentPageRecord(select) hook that always reads from the page’s own datasource, regardless of the block’s connected datasource. Similar to how useCurrentUser() works — but for the current page record.

This would be consistent with the existing mental model: useCurrentUser() gives you the user regardless of datasource, so useCurrentPageRecord() should give you the page record regardless of datasource.

Either of these options would unlock a whole class of context-aware blocks that need to both read context and write to a related table — a very common pattern in relational data models. Without it, blocks that span two related tables require unnecessary workarounds or architectural compromises.

Also, extending the functionality of useCurrentUser() would be fantastic. Right now this feature only returns profile fields (id, name, email, avatar), and no custom user fields. By making all user related fields available, like with the “Logged-in user” filter options, the VC block could be way more powerful IMHO (e.g. access to preferences, privileges, linked records, etc).

We are looking into this

This has been improved, the vibe coding block has now more context about the opened page

And this is now live, you can add multiple data sources to the vibe coding block :slight_smile:

Hi there!

Great you are implementing this.

I have trouble using it though and the AI is definitely not up to the point on that matter. It keeps bugging when trying to use two different sources.

I tried going from very simple code and asking an easy request.

My code V1:

import { datasource, useRecords, q } from "@/lib/datasource";
import { useCurrentUser } from "@/lib/user";

const ds = datasource.define({
  contact: "10883cb6-62e5-4182-aafc-6181f285a0b2",  // 👤 Contact
  team: "cfe65986-00bd-457f-a74b-a94052ebf1d3",      // 👥 Team
});

export default function Block() {
  const currentUser = useCurrentUser();
  console.log("[mesDuoz] currentUser", currentUser);

  return (
    <p>Hello</p>
  );
}

My request to the AI:

Modify the existing code to display two pieces of data:

From the team datasource, fetch all records and display the Name field of the first team.
From the contact datasource, fetch the record where the email matches the current user’s email, and display the Mail - if prénom field.

Use useRecords and q from @/lib/datasource, and useCurrentUser from @/lib/user. Keep the existing datasource.define() structure intact.

Answer:

I’ve updated the block to fetch and display:

  1. The Name field from the first team record

  2. The “Mail - if prénom” field from the contact record matching the current user’s email

The data will appear below the “Hello” text.

Code V2:

import { datasource, useRecords, q } from "@/lib/datasource";
import { useCurrentUser } from "@/lib/user";

const ds = datasource.define({
  contact: "10883cb6-62e5-4182-aafc-6181f285a0b2",  // 👤 Contact
  team: "cfe65986-00bd-457f-a74b-a94052ebf1d3",      // 👥 Team
});

const teamSelect = q.select({
  name: "Name",
});

const contactSelect = q.select({
  email: "Email",
  mailIfPrenom: "Mail - if prénom",
});

export default function Block() {
  const currentUser = useCurrentUser();
  console.log("[mesDuoz] currentUser", currentUser);

  const { data: teamData, status: teamStatus } = useRecords({
    from: ds.team,
    select: teamSelect,
    count: 1,
  });

  const { data: contactData, status: contactStatus } = useRecords({
    from: ds.contact,
    select: contactSelect,
    where: currentUser?.email ? q.text("email").is(currentUser.email) : undefined,
    count: 1,
  });

  const firstTeam = teamData?.pages[0]?.items[0];
  const userContact = contactData?.pages[0]?.items[0];

  return (
    <div className="container py-6">
      <div className="content space-y-4">
        <p>Hello</p>
        
        {teamStatus === "pending" && <div>Loading team data...</div>}
        {firstTeam && (
          <div>
            <strong>First Team Name:</strong> {firstTeam.fields.name}
          </div>
        )}
        
        {contactStatus === "pending" && <div>Loading contact data...</div>}
        {userContact && (
          <div>
            <strong>Mail - if prénom:</strong> {userContact.fields.mailIfPrenom}
          </div>
        )}
        
        {!currentUser?.email && (
          <div className="text-muted-foreground">Please log in to see your contact data</div>
        )}
      </div>
    </div>
  );
}

I get “Oh snap. This block couldn’t load. Use the side panel to review and fix the issue.”

→ What should I do to make multiple sources work in my code?
→ What repercussions does it have on CRUD fonctions, and how to define the source other than “from: ds.contact”?
→ Is there any documentation accessible on best practices to code directly. I am a developper and would love to be able to sometimes directly edit the custom code. I would need a clear documentation for that.

Thanks!

Hi Arthur,

Few things that stand out:

const teamSelect = q.select({
  name: "Name",
});

const contactSelect = q.select({
  email: "Email",
  mailIfPrenom: "Mail - if prénom",
});

Not sure why the AI used the field name instead of the field ID :thinking:

Also you have a filter:

where: currentUser?.email
  ? q.text("email").is(currentUser.email)
  : undefined

But It should be q.text("Email") (or, as I wrote above, more probably the field ID of the Email field), not "email"

Here is the Softr dev doc for vibe coding so you can check everything: