Can I implement SCD2 in dbt without using snapshots?

dbt snapshots’ columns are knowable in advance (it’s just the columns of your existing snapshot table plus the four bookkeeping columns dbt_scd_id, dbt_updated_at, dbt_valid_from and dbt_valid_to), so you could always pre-generate your tables and have dbt snapshot populate them.

With that said, keep in mind that unless you’re building everything as views, dbt run will also create tables…

I agree with @yoitsbenc - build a SCD2 table and then filter to current records (those where dbt_valid_to is null) in a downstream model to get the SCD1 equivalent.