Best way to separate private server/client constants?

I’m currently attempting to make a method of storing a certain extent of constants/initial data on the client but then storing the entire config file on the server for privacy; I’ll use the example of storing the data for a pet in a simulator game:

  1. All data is also on a serverside copy, including everything like Speed, Rarity and private values like a Template Model stored on the server.
  2. Speed and Rarity are replicated to the client however the private Template Model value is omitted from the client’s copy so that it can never be accessed.

Right now I’ve tried implementing this by having all constants stored in one serverside module that a client module fetches from using a RemoteFunction, but this rapidly gets complicated when each module grouping data for any other aspect of the game needs unique logic on what should values should be sent over to the client and what to omit.

Another issue rises when unrelated serverside code requires a replicated module that itself has fetched from the client’s copy; now that this config file is instead fetching data on the server’s behalf, the RemoteFunction that fetches the data from the serverside store will error!


I feel as though I am using the wrong approach to get to my goal, so instead of making an XY problem, I’ve tried to explain my goal first before my setbacks, but please let me know if you believe I’ve overlooked something. I’m just looking for advice/suggestions on a better approach on how to implement what I’m attempting, or if I’m on the right track and just messing up along the way.

Keeping data on the server is common practice, you dont want to keep sending data around so server sided you should keep a dictionary containing players and their data that updates when it changes, the client can request data using a remotefunction and as player is given when firing the server you can be sure its the player trying to get the info. In terms of exploits e.c.t the can see data sent to their client but not others.

So basically server side you store a chache of player data, and you do the same on each client that updates when it fires the server to do something for instance if you had a backpack, client side if they wanted to delete a item you would fire the server letting it know whats gettijg removed, and the server would return tje backpack with the item removed or in other words update the backpack

Using metatables is a great way of handling something like this as you can make your own functions e.c.t inside the metatable like a modulescript.

You only need to have data on the client so it knows what to display, the client should never control game logic e.g recieving coins for killing a npc, so its basically so the client knows what items it has in a inventory e.c.t.

If your struggling to do this its most likely because your code is not initially setup right.

This is not what I meant when I was talking about the type of data being stored; I meant moreso any constants that need to be used by other ModuleScripts, like I said in my example, being things like a type of pet and their Speed, Rarity and any private values. (I changed my “BirthDate” example as admittedly this is incorrect as obviously that isnt a constant for all pets)

I believe the metadata of metatables are lost when sent over the network and so this wouldn’t really work…

Yes, I want to save a copy of all game constants. Emphasis on copy, the server will have its own version and so any edits made on the client wont change the constants that are on the server.

well yeah this is literally the point of my post :sweat_smile:

Then send the data in the table not the whole table… just keeo it organised both server end and client end and its easy. Dictionary of info on server and on client, you can send the majoritt of the table but it shouod be in a function anyway cos of repeated use. Changes made on the client shouod be sent to the server, so the client just displays what you have, then you send a request to the server to do something with that data and the server does it and returns the updated table

Directly replicating from the client is very bad practice, the client basically requests changes and server does all the client has to do is display what option for changes there are.

Something I tend to do

local PlayerHandlers = {}
local PlayerHandler = {}

function PlayerHandler.New(Player)
    if not PlayerHandlers[Player] then
      PlayerHandlers[Player] = setmetatable({
         ["Player"] = Player,
         ["PlayerData"] ={}
      },{
         __Index = PlayerHandler
      })
    end
end

Then rather than sending metatable you return the players data from within the metatable. Cos the remotefunction gives player you can get it all thri the dictionary anywhere in the script.

Also handy for managing connections and keeping the relevant character. Being able to acess it from other scripts is kind of a non issue, it should just be on the same script to begin with or same script with modules for other functions. There are ways to still go across scripts but working around a issue doesnt actually resolve the issue, you need it on the same script realistically

Why are certain values so important to keep private? It shouldn’t matter if the client also knows server-only values, as long as you keep the code that handles them on the server.

Keeping things simple by moving your initial configurations (which I assume are never modified given how many times you refer to the data stored as constants) to ReplicatedStorage would solve a lot of the issues that arise here. One of the big ones is that you don’t have to manually replicate anything with remotes; the entire configuration will be replicated to the client when they connect.

I’m assuming you may have some data in the form of Instances in ServerStorage, which would produce errors when the client tries to index their paths at runtime. If your server-side Instances are all named uniquely, you can simply use ServerStorage:FindFirstChild(instanceName, true), which will always resolve to nil on the client.

If these values are constant, the client should be able to read them by themselves (from their local copy of the configuration); there’s no point in having the client request the server for something that should be available to them to begin with. That is, unless your constant value isn’t actually constant. If this is the case, then the question becomes one of replicating state.

1 Like

I already mentioned this becomes tedious when every time you invoke data you need custom logic on what values you want to omit and keep in the client’s shortened copy. This still seems like the only option to me though.


This wont be necessary, I’ve already reinstated that this is only for constants. No changes will be made on the client that the server will need to account for.


Did you really even read my original post…? I specifically state the server had a master module that contains all data, and the client simply requests its allowed portion of that data, so that the server can select which private values it doesnt want to share with the client. The client never sends back edits to be made, because its only allowed to fetch data.

I dont really know what you want me to tell you :sweat_smile: Constants; a table that never changes ~= Server handler cache; a table with values that will be read and written as the handler executes other methods

I can clearly tell you’re confused and talking about a completely different system because why would I need to read/write into a constant table with the key of a player if players only join during runtime???


As for your next paragraph, yes, I already said in my original post that there will be separate, unique ModuleScripts for simply holding the client & server copy and then any other module can access their data depending on what side of the client-server boundary its on.

Because in practice you may have other private values you want to keep hidden from clients?

I originally had all my constants on a single module in ReplicatedStorage like you’re describing but
adding any additional constants that shouldn’t replicate to the client is obviously a great security risk? I’m not sure why this isn’t obvious?


This is a fairer point and something I’ve considered doing but I’m trying to get at the fact that all these smaller issues seem to be caused simply by a poor approach at what I’m trying to achieve, hence my original post for guidance.


I’m intending for all data to originally be stored on the server such that the client NEEDS to request its own local copy to read from. This way I can securely omit private values from the original table before sending it off and ever being accessed by the client, and also have a single, safe module to write into any constants that may relate to a certain aspect of the game.

For now I’ll just go ahead with this approach and create any new post/reply if I have a particular issue because I’ve had nearly no actual advice/suggestions for the original goal I’ve mentioned.

How exactly does what you’re storing impose a security risk? If these values are already going to be given to the client, it takes minimal effort to find out what it is using a remote spy or something, they can also read each script’s environment.

If you really need values hidden from the client, what’s the problem with using a second module in server storage or something?

1 Like

What security risk? Ok, an exploiter decompiles your configuration file and sees there’s some named value that doesn’t appear to be used elsewhere by the client. So what? What are they going to do with it? They can change it all they’d like, and if your scripts are sensible (i.e. there’s no way for the client to somehow change to a server-only value on the server with a remote), nothing would happen.

If you keep the server-only values completely private, how does that change what the exploiter can and can’t do? The only difference is in the former, they get some very vague and incomplete knowledge of some values the server uses. They wouldn’t know exactly how or when the server uses them, just that it does, and that’s it.

But if you insist that there is some security risk, separate server-only values to a file in ServerStorage, like @7z99 suggested. Put a file in ReplicatedStorage containing only shared or client-side values, and put another file in ServerStorage containing the server-only ones. Then, on server runtime, use some table deep merge function to merge the shared values with the server-only values so the server gets a complete copy of the data it needs.

These are not constants, then, if you’re ever going to write to them? Do you mean read from?

If yes, the structure I suggest is having shared constant tables in ReplicatedStorage, server constant tables in ServerStorage, and 1 merged constant table in ReplicatedStorage (your single, safe module). The client will merge all tables (if you plan on having multiple; it’s much easier if you’re only using 1) in ReplicatedStorage, and the server will merge all tables in ReplicatedStorage and ServerStorage.

id say im confused as to why your trying to do this in a extremely inefficient and pointless way, put it on the same script and use remotes to pass the data, it really isnt complicated. essentially the system you are trying to create is a cache system to store the data ready for use. if you dont understand just ask rather than being snarky ‘did you read my post’. client is only supposed to fetch data or make requests which from the gist of gibberish looks like you do understand.

in very very simple terms of events between server and client:

  1. ServerStart - Along with beggining the script, does not guaranteed players are there or anything
  2. Client Joins - Client Does not have the data
  3. Server detects player joining and starts loading the players data into the server cache
  4. Client Fires RemoteFunction asking for the data
  5. Server gets the data from the cache and sends it to the client
  6. Client can then Cache the returned data so it can be displayed on demand.

the server cache is not directly connected to the client cache so they can have different sets of data, meaning the server is not exploitable, and the client wont have any info it shouldnt have. in terms of security you choose every piece of data that gets to the client, they can only use the data given to them by the server, which is 100% safe from exploiters unless its sent to them thro the remote. so basically only send the information you intend to send, pretty straight foward I think. And all the exploiters can do with information coming from the server to the client is read it, it does not give them access to the server, all server communictions would go through this essentially making a barrier between your information on the server and the clients. The remotefunction just handles what can pass through that barrier.

in terms of exploits they can edit data being sent through remotes or variables e.c.t, the client can hold false information and it doesnt matter, the client cant request changes to the servers set of data unless you set it up to do so. The reason you want to cache it rather than repeatidly ask the server for the information is so that your not inducing delays by waiting on remotes.

In terms of interacting with said dataset, you can still request changes from the client like shop purchases if the sanity check is done server sided. for example

  1. Player Clicks GUI to buy item
  2. fires server with Buy X item
  3. Server checks if the player has the funds to buy the item, and if they do it gives it to them and subtracts the money from the players data and returns the new set of playerdata to update the client.

if this isnt clear then try and narrow down what exactly doesnt add up for you and ill be happy to anwser any questions (dont take loads of quotes e.c.t and split up random comments, it looks like gibberish just ask normally XD)